Generated from the current hyperproc 0.1.2 checkout.
Implementation: hyperproc/atmos/setup.py. Signatures, defaults, docstrings, and expandable source are extracted statically; the module is not imported or executed. Names beginning with _ are implementation details, not a stable public API.
Use the function signature as the authority for individual parameter defaults and return annotations. Original docstrings sometimes group parameter names or wrap return descriptions across lines; these descriptions are preserved rather than inferred or rewritten.
One-time environment setup and health check for :mod:hyperproc.atmos.
ISOFIT is a pip package, but the radiative-transfer engines it drives are not:
6S is Fortran that must be compiled on the machine, sRTMnet is a 5.5 GB set
of emulator weights, LibRadTran is a compiled C/Fortran package, and the data
and surface libraries add another ~100 MB. ISOFIT keeps all of them under one
base directory named in ~/.isofit/isofit.ini. On a shared machine point
every user at one base (setup(base="/data/.../isofit_assets")) so the
assets are fetched once.
:func:check reports what is installed and what is missing. It never
downloads anything.
:func:setup fetches (and compiles) what the requested engines need, then
runs :func:check.
hyperproc-atmos-setup is the command-line form of :func:setup.
deflibradtran_exe(path)->Path|None:"""``bin/uvspec`` under a libRadtran asset directory, or None when unbuilt."""base=Path(path)forcandin[base]+sorted(pforpinbase.glob("*")ifp.is_dir()):exe=cand/"bin"/"uvspec"ifexe.is_file():returnexereturnNone
Configure and compile an unpacked libRadtran tree.
libRadtran needs the GNU Scientific Library and netCDF at build time.
ISOFIT's own build step runs ./configure && make without checking
either, and silently leaves no binary when GSL is missing. This builds
against the libraries of the running conda environment (sys.prefix;
conda install -c conda-forge gsl supplies GSL) and verifies that
bin/uvspec exists afterwards.
defbuild_libradtran(path,jobs:int=8,verbose:bool=True)->Path:"""Configure and compile an unpacked libRadtran tree. libRadtran needs the GNU Scientific Library and netCDF at build time. ISOFIT's own build step runs ``./configure && make`` without checking either, and silently leaves no binary when GSL is missing. This builds against the libraries of the running conda environment (``sys.prefix``; ``conda install -c conda-forge gsl`` supplies GSL) and verifies that ``bin/uvspec`` exists afterwards. """importosimportsubprocessbase=Path(path)trees=[pforpin[base]+sorted(base.glob("*"))if(p/"configure").is_file()]ifnottrees:raiseFileNotFoundError(f"no libRadtran source tree (configure script) under {base}; run isofit download libradtran")tree=trees[0]prefix=Path(sys.prefix)env=dict(os.environ)env["PATH"]=f"{prefix/'bin'}:{env.get('PATH','')}"env["CPPFLAGS"]=f"-I{prefix/'include'}{env.get('CPPFLAGS','')}".strip()env["LDFLAGS"]=f"-L{prefix/'lib'} -Wl,-rpath,{prefix/'lib'}{env.get('LDFLAGS','')}".strip()# The tarball ships pre-generated dependency lists (src/.depend) that name# the developers' /usr/include/gsl headers; make then fails looking for# them. They are regenerated by the build, so drop the shipped copies.fordepintree.rglob(".depend"):try:if"/usr/include"indep.read_text(errors="replace"):dep.unlink()exceptOSError:passlog=tree/"hyperproc_build.log"withopen(log,"w")asfh:forcmdin(["./configure","--with-netcdf4=yes"],["make",f"-j{int(jobs)}"]):ifverbose:print(f"libradtran: {' '.join(cmd)} (log {log})",flush=True)proc=subprocess.run(cmd,cwd=str(tree),env=env,stdout=fh,stderr=subprocess.STDOUT)ifproc.returncode!=0:tail="\n".join(log.read_text(errors="replace").splitlines()[-15:])raiseRuntimeError(f"libRadtran {cmd[0]} failed (exit {proc.returncode}); tail of {log}:\n{tail}")exe=libradtran_exe(base)ifexeisNone:raiseRuntimeError(f"libRadtran built without error but bin/uvspec is missing under {tree}; see {log}")returnexe
What the atmospheric-correction stack has and lacks, for engines.
Returns a dict with isofit (version or None), ini, base,
compilers, assets (per ISOFIT key: path, ok, exe) and missing
(human-readable items with the command that supplies each). ok is
True when nothing is missing. Nothing is downloaded or written.
defcheck(engines=("sRTMnet",),verbose:bool=True)->dict:"""What the atmospheric-correction stack has and lacks, for ``engines``. Returns a dict with ``isofit`` (version or None), ``ini``, ``base``, ``compilers``, ``assets`` (per ISOFIT key: path, ok, exe) and ``missing`` (human-readable items with the command that supplies each). ``ok`` is True when nothing is missing. Nothing is downloaded or written. """report={"python":sys.version.split()[0],"isofit":None,"ini":None,"base":None,"compilers":{},"assets":{},"missing":[],"ok":False}iso=_isofit()ifisoisNone:report["missing"].append(f"isofit: {PIP_HINT}")_report(report,verbose)returnreportreport["isofit"]=iso.__version__fromisofit.dataimportenvreport["ini"]=str(env.ini)report["base"]=str(getattr(env,"base",""))orNoneforrcinunterminated_rc_files():report["missing"].append(f"{rc}: printf '\\n' >> {rc} (no newline at the end; netCDF-C "f"reads past it and ISOFIT's workers crash at random)")needed_tools=sorted({tforkin_assets_for(engines)fortinCOMPILERS.get(k,())})fortoolinneeded_tools:# the conda environment's own bin (gsl-config lives there) counts even when it is not on PATHreport["compilers"][tool]=shutil.which(tool)orshutil.which(tool,path=str(Path(sys.prefix)/"bin"))ifreport["compilers"][tool]isNone:pkg="gsl"iftool=="gsl-config"elsetoolreport["missing"].append(f"{tool}: conda install -c conda-forge {pkg} (needed to build the engine)")forkeyin_assets_for(engines):path=env[key]entry={"path":path,"ok":False}try:mod=importlib.import_module(f"isofit.data.cli.{key}")entry["ok"]=bool(mod.validate(path,checkForUpdate=False,debug=_quiet,error=_quiet))exceptExceptionasexc:# a broken install must show as missing, not crash the checkentry["error"]=f"{type(exc).__name__}: {exc}"ifentry["ok"]andkey=="sixs":fromisofit.data.cli.sixsimportget_exeentry["exe"]=str(get_exe(path))ifentry["ok"]andkey=="libradtran":# ISOFIT's validator accepts an unpacked, unbuilt tree; the engine needs bin/uvspecexe=libradtran_exe(path)ifexeisNone:entry["ok"]=Falseentry["error"]="source unpacked but not built (no bin/uvspec)"report["missing"].append(f"{key}: build failed or not run; hyperproc-atmos-setup --engine LibRadTran "f"builds it against the conda GSL/netCDF (needs gcc, gfortran, make, gsl)")report["assets"][key]=entrycontinueentry["exe"]=str(exe)ifnotentry["ok"]:report["missing"].append(f"{key}: isofit download {key} -> {path}")report["assets"][key]=entryreport["ok"]=notreport["missing"]_report(report,verbose)returnreport
Fetch and build what engines need, then :func:check.
PARAMETER
DESCRIPTION
base
directory to hold every ISOFIT asset. Recorded in
~/.isofit/isofit.ini so ISOFIT and every later call find it;
None keeps the current ini setting (default ~/.isofit).
TYPE:str | NoneDEFAULT:None
engines
which engines to provision. "sRTMnet" (default) is the
emulator JPL uses operationally and needs 6S compiled underneath.
DEFAULT:('sRTMnet',)
examples
also download ISOFIT's tutorial data (~340 MB), useful for
an end-to-end smoke test of a fresh install.
defsetup(base:str|None=None,engines=("sRTMnet",),examples:bool=False,overwrite:bool=False,verbose:bool=True)->dict:"""Fetch and build what ``engines`` need, then :func:`check`. Args: base: directory to hold every ISOFIT asset. Recorded in ``~/.isofit/isofit.ini`` so ISOFIT and every later call find it; None keeps the current ini setting (default ``~/.isofit``). engines: which engines to provision. ``"sRTMnet"`` (default) is the emulator JPL uses operationally and needs 6S compiled underneath. examples: also download ISOFIT's tutorial data (~340 MB), useful for an end-to-end smoke test of a fresh install. overwrite: re-download assets that validate fine. Raises: ImportError: ISOFIT is not installed. RuntimeError: a compiler an engine needs is missing. """iso=_isofit()ifisoisNone:raiseImportError(f"ISOFIT is not installed: {PIP_HINT}")fromisofit.dataimportenvifbase:Path(base).expanduser().mkdir(parents=True,exist_ok=True)env.changeBase(str(Path(base).expanduser().resolve()))env.save(diff_only=False)ifverbose:print(f"ISOFIT assets base -> {env.base} (saved to {env.ini})")forrcinunterminated_rc_files():ifterminate_rc_file(rc)andverbose:print(f"{rc}: added the missing newline at the end of the file "f"(netCDF-C reads past a last line without one)")keys=_assets_for(engines)missing_tools=[tforkinkeysfortinCOMPILERS.get(k,())ifshutil.which(t)isNoneandshutil.which(t,path=str(Path(sys.prefix)/"bin"))isNone]ifmissing_tools:raiseRuntimeError(f"cannot build the engines without {sorted(set(missing_tools))}; "f"install them first (conda install -c conda-forge {' '.join(sorted(set(missing_tools)))})")forkeyinkeys:mod=importlib.import_module(f"isofit.data.cli.{key}")ifnotoverwriteandmod.validate(env[key],checkForUpdate=False,debug=_quiet,error=_quiet):ifverbose:print(f"{key}: already present at {env[key]}")continueifkey=="libradtran"andnotoverwriteandPath(env[key]).exists()andlibradtran_exe(env[key])isNone:ifverbose:print(f"{key}: source present but not built -> compiling")build_libradtran(env[key],verbose=verbose)continueifverbose:print(f"{key}: downloading{' and building'ifkeyinCOMPILERSelse''} -> {env[key]}")mod.download(overwrite=overwrite)ifkey=="libradtran"andlibradtran_exe(env[key])isNone:build_libradtran(env[key],verbose=verbose)ifexamples:fromisofit.data.cliimportexamplesasexex.download(overwrite=overwrite)returncheck(engines,verbose=verbose)
defmain(argv=None)->int:"""``hyperproc-atmos-setup``: provision the ISOFIT stack, or just check it."""importargparsep=argparse.ArgumentParser(prog="hyperproc-atmos-setup",description="Fetch and build the ISOFIT engines and assets hyperproc.atmos needs.")p.add_argument("--base",help="directory for all ISOFIT assets; default ~/.isofit. On a shared machine give every user the same one so the assets are fetched once")p.add_argument("--engine",action="append",choices=ENGINES,help="engine(s) to provision; default sRTMnet")p.add_argument("--examples",action="store_true",help="also fetch ISOFIT's tutorial data")p.add_argument("--overwrite",action="store_true",help="re-download assets that already validate")p.add_argument("--check",action="store_true",help="only report what is present; download nothing")a=p.parse_args(argv)engines=tuple(a.engine)ifa.engineelse("sRTMnet",)try:report=check(engines)ifa.checkelsesetup(a.base,engines,a.examples,a.overwrite)except(ImportError,RuntimeError,ValueError)asexc:print(f"error: {exc}",file=sys.stderr)return2return0ifreport["ok"]else1