Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 53 additions & 13 deletions climate_tookit/fetch_data/preprocess_data/preprocess_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,31 @@

from transform_data import transform_data
from sources.utils.models import ClimateVariable, ClimateDataset
from sources.nex_gddp import AVAILABLE_MODELS as NEX_GDDP_MODELS


def resolve_models(model, models):
"""Resolve --model/--models into a list. 'all' = every NEX-GDDP model;
returns [None] when no model was requested (non-NEX-GDDP sources)."""
if models:
spec = models.strip()
if spec.lower() == 'all':
return list(NEX_GDDP_MODELS)
names = [m.strip() for m in spec.split(',') if m.strip()]
unknown = [m for m in names if m not in NEX_GDDP_MODELS]
if unknown:
raise ValueError(
f"Unknown model(s): {', '.join(unknown)}. "
f"Available: {', '.join(NEX_GDDP_MODELS)}"
)
return names
return [model]


def _suffix_path(path, suffix):
"""Insert '_<suffix>' before the file extension."""
stem, ext = os.path.splitext(path)
return f"{stem}_{suffix}{ext}"


def clean_climate_data(df: pd.DataFrame) -> pd.DataFrame:
Expand Down Expand Up @@ -174,6 +199,10 @@ def save_output(data, output_path, fmt):
parser.add_argument("--start", type=str)
parser.add_argument("--end", type=str)
parser.add_argument("--model", type=str)
parser.add_argument("--models", type=str, default=None,
help="NEX-GDDP only. Comma-separated models, or 'all'. "
"Saves one file per model (output stem + _<model>). "
"Overrides --model.")
parser.add_argument("--scenario", type=str)
parser.add_argument("-o", "--output", default=None)
parser.add_argument(
Expand All @@ -188,20 +217,31 @@ def save_output(data, output_path, fmt):
date_from = date.fromisoformat(args.start) if args.start else None
date_to = date.fromisoformat(args.end) if args.end else None

df = preprocess_data(
source=args.source,
location_coord=location_coord,
date_from=date_from,
date_to=date_to,
model=args.model,
scenario=args.scenario
)
try:
model_list = resolve_models(args.model, args.models)
except ValueError as exc:
print(f"Error: {exc}")
sys.exit(1)
multi = len(model_list) > 1

for model in model_list:
if multi:
print(f"\n=== NEX-GDDP model: {model} ===")
df = preprocess_data(
source=args.source,
location_coord=location_coord,
date_from=date_from,
date_to=date_to,
model=model,
scenario=args.scenario
)

if args.format == "print" or not args.output:
print(df)
else:
save_output(df, args.output, args.format)
print(f"Saved to {args.output}")
if args.format == "print" or not args.output:
print(df)
else:
out_path = _suffix_path(args.output, model) if multi else args.output
save_output(df, out_path, args.format)
print(f"Saved to {out_path}")


# python climate_tookit/fetch_data/preprocess_data/preprocess_data.py --source era_5 --lon 36.8 --lat -1.3 --start 2020-01-01 --end 2020-03-05
Expand Down
82 changes: 63 additions & 19 deletions climate_tookit/fetch_data/source_data/source_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from sources.tamsat import DownloadTAMSAT
from sources.nasa_power import DownloadData as DownloadNASA
from sources.nex_gddp import DownloadData as DownloadNEXGDDP
from sources.nex_gddp import AVAILABLE_MODELS as NEX_GDDP_MODELS
from sources.soil_grid import DownloadData as DownloadSoilGrid
from sources.utils.models import ClimateDataset, ClimateVariable, SoilVariable, Location
from sources.utils.settings import Settings
Expand Down Expand Up @@ -109,6 +110,31 @@ def save_output(data, output_path, fmt):
else:
raise ValueError(fmt)

def resolve_models(model, models):
"""Resolve the requested model list from --model/--models.

Returns a list of model names (or [None] when no model was requested, e.g.
for non-NEX-GDDP sources). 'all' expands to every available NEX-GDDP model.
"""
if models:
spec = models.strip()
if spec.lower() == 'all':
return list(NEX_GDDP_MODELS)
names = [m.strip() for m in spec.split(',') if m.strip()]
unknown = [m for m in names if m not in NEX_GDDP_MODELS]
if unknown:
raise ValueError(
f"Unknown model(s): {', '.join(unknown)}. "
f"Available: {', '.join(NEX_GDDP_MODELS)}"
)
return names
return [model]

def _suffix_path(path, suffix):
"""Insert '_<suffix>' before the file extension (foo.csv -> foo_GFDL.csv)."""
stem, ext = os.path.splitext(path)
return f"{stem}_{suffix}{ext}"

def main():
parser = argparse.ArgumentParser(description='Download climate data')
parser.add_argument('--lon', type=float, required=True)
Expand All @@ -117,7 +143,13 @@ def main():
parser.add_argument('--variables', required=True)
parser.add_argument('--from', dest='date_from', required=True)
parser.add_argument('--to', dest='date_to', required=True)
parser.add_argument('--model', default=None)
parser.add_argument('--model', default=None,
help='Single NEX-GDDP model (e.g. GFDL-ESM4).')
parser.add_argument('--models', default=None,
help="NEX-GDDP only. Comma-separated models, or 'all' "
"for every available model. Fetches each model and "
"saves one file per model (output stem + _<model>). "
"Overrides --model.")
parser.add_argument('--scenario', default=None)
parser.add_argument('--output', '-o', default=None)
parser.add_argument(
Expand Down Expand Up @@ -157,24 +189,36 @@ def main():

settings = Settings.load()

source_data = SourceData(
location_coord=(args.lat, args.lon),
variables=variables,
source=source,
date_from_utc=date_from,
date_to_utc=date_to,
settings=settings,
model=args.model,
scenario=args.scenario
)

climate_data = source_data.download()

if args.format == "print" or not args.output:
print(climate_data.to_string())
else:
save_output(climate_data, args.output, args.format)
print(f"Saved to {args.output}")
try:
model_list = resolve_models(args.model, args.models)
except ValueError as exc:
print(f"Error: {exc}")
return 1
multi = len(model_list) > 1

for model in model_list:
if multi:
print(f"\n=== NEX-GDDP model: {model} ===")
source_data = SourceData(
location_coord=(args.lat, args.lon),
variables=variables,
source=source,
date_from_utc=date_from,
date_to_utc=date_to,
settings=settings,
model=model,
scenario=args.scenario
)

climate_data = source_data.download()

if args.format == "print" or not args.output:
print(climate_data.to_string())
else:
# One file per model when multiple are requested.
out_path = _suffix_path(args.output, model) if multi else args.output
save_output(climate_data, out_path, args.format)
print(f"Saved to {out_path}")

return 0

Expand Down
49 changes: 30 additions & 19 deletions climate_tookit/fetch_data/transform_data/transform_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

sys.path.append(os.path.join(os.path.dirname(__file__), "..", "source_data"))

from source_data import SourceData
from source_data import SourceData, resolve_models, _suffix_path
from sources.utils.models import ClimateVariable, ClimateDataset, SoilVariable
from sources.utils.settings import Settings

Expand Down Expand Up @@ -171,6 +171,10 @@ def save_output(data, output_path, fmt):
parser.add_argument("--start", type=str)
parser.add_argument("--end", type=str)
parser.add_argument("--model", type=str)
parser.add_argument("--models", type=str, default=None,
help="NEX-GDDP only. Comma-separated models, or 'all'. "
"Saves one file per model (output stem + _<model>). "
"Overrides --model.")
parser.add_argument("--scenario", type=str)
parser.add_argument("-o", "--output", default=None)
parser.add_argument("--format", choices=["csv", "json", "print"], default="print")
Expand All @@ -186,13 +190,20 @@ def save_output(data, output_path, fmt):
date_from = date.fromisoformat(args.start) if args.start else None
date_to = date.fromisoformat(args.end) if args.end else None

try:
model_list = resolve_models(args.model, args.models)
except ValueError as exc:
print(f"Error: {exc}")
sys.exit(1)
multi = len(model_list) > 1

errors = validate_inputs(
args.source,
args.lat,
args.lon,
date_from,
date_to,
args.model,
model_list[0],
args.scenario,
)

Expand All @@ -202,24 +213,24 @@ def save_output(data, output_path, fmt):
print(f" - {err}")
sys.exit(1)

location_coord = (args.lat, args.lon)
date_from = date.fromisoformat(args.start) if args.start else None
date_to = date.fromisoformat(args.end) if args.end else None

df = transform_data(
source=args.source,
location_coord=location_coord,
date_from=date_from,
date_to=date_to,
model=args.model,
scenario=args.scenario,
)
for model in model_list:
if multi:
print(f"\n=== NEX-GDDP model: {model} ===")
df = transform_data(
source=args.source,
location_coord=location_coord,
date_from=date_from,
date_to=date_to,
model=model,
scenario=args.scenario,
)

if args.format == "print" or not args.output:
print(df)
else:
save_output(df, args.output, args.format)
print(f"Saved to {args.output}")
if args.format == "print" or not args.output:
print(df)
else:
out_path = _suffix_path(args.output, model) if multi else args.output
save_output(df, out_path, args.format)
print(f"Saved to {out_path}")

# python climate_tookit/fetch_data/transform_data/transform_data.py --source era_5 --lon 36.817223 --lat -1.286389 --start 2020-01-01 --end 2020-03-05

Expand Down
Loading