From 7f137c0fe1bb35c3c8df5c21286732e820fb73eb Mon Sep 17 00:00:00 2001 From: Patrick Brown <25125211+patrickbrown4@users.noreply.github.com> Date: Tue, 20 Oct 2026 15:34:10 -0600 Subject: [PATCH 1/5] move cluster check to reeds.slurm.get_cluster() and slurm check to reeds.slurm.check_slurm() --- helpers/interim_report_batch.py | 2 +- helpers/restart_runs.py | 2 +- hourlize/run_hourlize.py | 26 +++++++---------- postprocessing/combine_runs/combine_runs.py | 2 +- postprocessing/run_pcm.py | 16 +---------- postprocessing/run_reeds2pras.py | 12 +++----- reeds/__init__.py | 1 + reeds/io.py | 4 +-- reeds/slurm.py | 29 +++++++++++++++++++ runreeds.py | 32 ++++++++++----------- tests/get_subset_h5.py | 2 +- 11 files changed, 67 insertions(+), 61 deletions(-) create mode 100644 reeds/slurm.py diff --git a/helpers/interim_report_batch.py b/helpers/interim_report_batch.py index b342fa85d..909f0f5bb 100644 --- a/helpers/interim_report_batch.py +++ b/helpers/interim_report_batch.py @@ -26,7 +26,7 @@ parser.add_argument('--batch_name', '-b', type=str, default='', help='Prefix for batch of runs') args = parser.parse_args() # check if on hpc -hpc = True if (int(os.environ.get('REEDS_USE_SLURM',0))) else False +hpc = reeds.slurm.check_slurm() # get list of cases with matching batch name case_list = glob(os.path.join('runs', '*')) diff --git a/helpers/restart_runs.py b/helpers/restart_runs.py index f1132e2e3..be17277a2 100644 --- a/helpers/restart_runs.py +++ b/helpers/restart_runs.py @@ -145,7 +145,7 @@ f.writelines(line + '\n') # Check if we are going to run this in parallel or not -hpc = True if (int(os.environ.get('REEDS_USE_SLURM',0))) else False +hpc = reeds.slurm.check_slurm() if hpc and len(runs_failed) > 1: # On HPC with multiple cases cases_per_node = int(input('Number of simultaneous runs per node [integer]: ')) diff --git a/hourlize/run_hourlize.py b/hourlize/run_hourlize.py index b5d8b1116..d07437f9b 100644 --- a/hourlize/run_hourlize.py +++ b/hourlize/run_hourlize.py @@ -17,7 +17,11 @@ import sys import traceback import copy_rev_folders +from pathlib import Path from collections import OrderedDict +sys.path.append(str(Path(__file__).parent.parent)) +import reeds + #%% =========================================================================== ### --- FUNCTIONS --- @@ -26,16 +30,14 @@ def get_remote_path(local): """detect path to supply curve files either on the HPC or nrelnas01""" # remote path for supply curves - hpc = True if ('NREL_CLUSTER' in os.environ) else False + hpc = reeds.slurm.check_slurm() if hpc: #For running hourlize on the HPC link to shared-projects folder - if os.environ.get('NREL_CLUSTER') == 'kestrel': + cluster = reeds.slurm.get_cluster() + if cluster == 'kestrel': remotepath = '/kfs2/shared-projects/reeds' - elif os.environ.get('NREL_CLUSTER') == 'eagle': - remotepath = '/shared-projects/reeds' else: - raise Exception(f"Detected {os.environ.get('NREL_CLUSTER')} as NLR Cluster; " - "only 'eagle' and 'kestrel' are supported") + raise ValueError(f"Unsupported cluster: {cluster}") else: # if not on the hpc running link to nrelnas01 and set local to true remotepath = os.path.join( @@ -165,13 +167,9 @@ def launch_batch_file(casename, configpath, outpath, args, copy_from_rev=False): # setup script to run each case ext = '.sh' if os.name == 'posix' else '.bat' with open(os.path.join(outpath, casename + "_run" + ext), 'w+') as OPATH: - if os.environ.get('NREL_CLUSTER') == 'kestrel': - OPATH.writelines("source /nopt/nrel/apps/env.sh \n") - OPATH.writelines("module load anaconda3 \n") - OPATH.writelines("conda activate reeds \n\n") - elif os.environ.get('NREL_CLUSTER') == 'eagle': - OPATH.writelines("module load conda \n") - OPATH.writelines("conda activate reeds \n\n") + OPATH.writelines("source /nopt/nrel/apps/env.sh \n") + OPATH.writelines("module load anaconda3 \n") + OPATH.writelines("conda activate reeds \n\n") # run hourlize OPATH.writelines(f"cd {hourlize_path}\n") callstring = f"python {args.mode}.py --config {configpath}" @@ -182,8 +180,6 @@ def launch_batch_file(casename, configpath, outpath, args, copy_from_rev=False): callstring += "\n" OPATH.writelines(callstring) - - # launch run locally or submit to hpc if args.local: if args.nosubmit: diff --git a/postprocessing/combine_runs/combine_runs.py b/postprocessing/combine_runs/combine_runs.py index 3405d9a89..aa6b55a2b 100644 --- a/postprocessing/combine_runs/combine_runs.py +++ b/postprocessing/combine_runs/combine_runs.py @@ -369,7 +369,7 @@ def main(reeds_path, batch_name, folder_name_suffix, runlist, keywords, local, d combine_case = cases.loc[cases.scenario == scen].copy() combine_case.to_csv(os.path.join(output_path, 'cases_combined.csv'), index=False) # check if run should be submitted to HPC or run directly - hpc = True if ('NREL_CLUSTER' in os.environ) else False + hpc = reeds.slurm.check_slurm() if hpc and local: print( "Note: you are on the HPC but are running locally on your current node. " diff --git a/postprocessing/run_pcm.py b/postprocessing/run_pcm.py index 1186f1c19..d499443c2 100644 --- a/postprocessing/run_pcm.py +++ b/postprocessing/run_pcm.py @@ -31,20 +31,6 @@ # %% Functions -def check_slurm(forcelocal=False): - """Check whether to submit slurm jobs (if on HPC) or run locally""" - hpc = ( - False - if forcelocal - else ( - True - if int(os.environ.get('REEDS_USE_SLURM', 0)) and ('NREL_CLUSTER' in os.environ) - else False - ) - ) - return hpc - - def solvestring_pcm( batch_case, sw, @@ -367,7 +353,7 @@ def main(casepath, t, switch_mods=switch_mods_default, label='', overwrite=False # bigmem = True # %% Determine whether to submit slurm job - hpc = check_slurm(forcelocal=forcelocal) + hpc = reeds.slurm.check_slurm(forcelocal=forcelocal) ### Run it if not hpc: diff --git a/postprocessing/run_reeds2pras.py b/postprocessing/run_reeds2pras.py index b5f6d87bc..01d64b602 100644 --- a/postprocessing/run_reeds2pras.py +++ b/postprocessing/run_reeds2pras.py @@ -1,22 +1,18 @@ #%% Imports import pandas as pd import os +import sys import site import json from glob import glob import subprocess ### Local imports reeds_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +sys.path.append(reeds_path) +import reeds #%%### Functions -def check_slurm(forcelocal=False): - """Check whether to submit slurm jobs (if on HPC) or run locally""" - hpc = True if (int(os.environ.get('REEDS_USE_SLURM',0))) else False - hpc = False if forcelocal else hpc - return hpc - - def submit_job( case, year=0, @@ -241,7 +237,7 @@ def main( # switch_mods = {} #%% Determine whether to submit SLURM job - hpc = check_slurm(forcelocal=local) + hpc = reeds.slurm.check_slurm(forcelocal=local) ### Run it if hpc: diff --git a/reeds/__init__.py b/reeds/__init__.py index ff723dfd1..c551a70a0 100644 --- a/reeds/__init__.py +++ b/reeds/__init__.py @@ -14,6 +14,7 @@ from . import remote as remote from . import report_utils as report_utils from . import results as results +from . import slurm as slurm from . import spatial as spatial from . import techs as techs from . import timeseries as timeseries diff --git a/reeds/io.py b/reeds/io.py index a6df6b48e..90b3b0c99 100644 --- a/reeds/io.py +++ b/reeds/io.py @@ -21,7 +21,7 @@ if 'runs' in reeds_path.split(os.path.sep): reeds_path = reeds_path[: reeds_path.index(os.sep + 'runs' + os.sep)] -hpc = True if ('NREL_CLUSTER' in os.environ) else False +hpc = reeds.slurm.check_slurm() # ######## ######## ### ######## # ## ## ## ## ## ## ## @@ -756,7 +756,7 @@ def get_switches(case=None, **kwargs): threads = get_param_value(fpath_opt, "threads", dtype=int) sw['threads'] = threads ## Determine whether run is on HPC - sw['hpc'] = True if int(os.environ.get('REEDS_USE_SLURM', 0)) else False + sw['hpc'] = reeds.slurm.check_slurm() ## Add the run location sw['casedir'] = case sw['reeds_path'] = reeds_path if case is None else os.path.dirname(os.path.dirname(case)) diff --git a/reeds/slurm.py b/reeds/slurm.py new file mode 100644 index 000000000..add85dfe0 --- /dev/null +++ b/reeds/slurm.py @@ -0,0 +1,29 @@ +### Imports +import os + + +### Functions +def get_cluster(): + """ + Return the name of the HPC cluster if on a cluster. + If not on a cluster, return None. + """ + name_fields = ['NREL_CLUSTER', 'NLR_CLUSTER'] + ## Keep the first match in name_fields + for name_field in name_fields: + out = os.environ.get(name_field) + if out: + break + return out + + +def check_slurm(forcelocal=False): + """Check whether to submit slurm jobs (if on HPC) or run locally""" + if forcelocal: + hpc = False + else: + if os.environ.get('REEDS_USE_SLURM') and get_cluster(): + hpc = True + else: + hpc = False + return hpc diff --git a/runreeds.py b/runreeds.py index 1572ce3ef..41f4bd7f9 100644 --- a/runreeds.py +++ b/runreeds.py @@ -147,8 +147,8 @@ def get_ivt_numclass(reeds_path, casedir, caseSwitches): def get_rev_paths(revswitches): # Expand on reV path based on where this run is happening # when running on the HPC this links to the shared-projects folder - hpc = True if (int(os.environ.get('REEDS_USE_SLURM',0))) else False - if os.environ.get('NREL_CLUSTER') == 'kestrel': + hpc = reeds.slurm.check_slurm() + if reeds.slurm.get_cluster() == 'kestrel': hpc_path = '/kfs2/shared-projects/reeds/Supply_Curve_Data' else: hpc_path = '/shared-projects/reeds/Supply_Curve_Data' @@ -833,15 +833,19 @@ def setupEnvironment( cases_suffix = str(input('Case Suffix: ')) #%% Check whether to submit slurm jobs (if on HPC) or run locally - hpc = True if (int(os.environ.get('REEDS_USE_SLURM',0))) else False - hpc = False if forcelocal else hpc + hpc = reeds.slurm.check_slurm(forcelocal=forcelocal) ### If on NLR HPC but NOT submitting slurm job, ask for confirmation - if ('NREL_CLUSTER' in os.environ) and (not hpc): + if reeds.slurm.get_cluster() and (not hpc): print( "It looks like you're running on the NLR HPC but the REEDS_USE_SLURM environment " "variable is not set to 1, meaning the model will run locally rather than being " - "submitted as a slurm job. Are you sure you want to run locally?" + "submitted as a slurm job. Are you sure you want to run locally? " + "If not:\n" + " Add `export REEDS_USE_SLURM=1` to your ~/.bashrc file\n" + " Run `source ~/.bashrc`\n" + " Run `conda activate reeds` to reactivate the environment\n" + " Rerun this script" ) confirm_local = str(input('Run job locally? y/[n]: ') or 'n') if confirm_local not in ['y','Y','yes','Yes','YES']: @@ -1278,17 +1282,11 @@ def write_batch_script( comment('Set up nodal environment for run', OPATH) OPATH.writelines(". $HOME/.bashrc \n") OPATH.writelines("module purge \n") - - if os.environ.get('NREL_CLUSTER') == 'kestrel': - OPATH.writelines("source /nopt/nrel/apps/env.sh \n") - OPATH.writelines("module load anaconda3 \n") - OPATH.writelines("module use /nopt/nrel/apps/software/gams/modulefiles \n") - OPATH.writelines("module load gams \n") - OPATH.writelines("module load julia/1.12.1 \n") - else: - OPATH.writelines("module load conda \n") - OPATH.writelines("module load gams \n") - + OPATH.writelines("source /nopt/nrel/apps/env.sh \n") + OPATH.writelines("module load anaconda3 \n") + OPATH.writelines("module use /nopt/nrel/apps/software/gams/modulefiles \n") + OPATH.writelines("module load gams \n") + OPATH.writelines("module load julia/1.12.1 \n") OPATH.writelines("conda activate reeds \n") OPATH.writelines('export R_LIBS_USER="$HOME/rlib" \n\n\n') diff --git a/tests/get_subset_h5.py b/tests/get_subset_h5.py index eb91a2d99..6f2a50332 100644 --- a/tests/get_subset_h5.py +++ b/tests/get_subset_h5.py @@ -32,7 +32,7 @@ ] # series of paths to updated county h5 files -hpc = True if ('NREL_CLUSTER' in os.environ) else False +hpc = reeds.slurm.check_slurm() if hpc: remotepath = '/kfs2/shared-projects/reeds' #kestrel else: From 6d6fd30c20ccaf96891afb78e23dec139540e301 Mon Sep 17 00:00:00 2001 From: Patrick Brown <25125211+patrickbrown4@users.noreply.github.com> Date: Tue, 20 Oct 2026 15:39:33 -0600 Subject: [PATCH 2/5] don't call check_slurm() in reeds.io --- hourlize/write_site_parameters.py | 2 +- reeds/io.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/hourlize/write_site_parameters.py b/hourlize/write_site_parameters.py index bfa6b18de..4bbeda5ab 100644 --- a/hourlize/write_site_parameters.py +++ b/hourlize/write_site_parameters.py @@ -26,7 +26,7 @@ def check_negative_values(df, cost_cols): ) #%%### Fixed inputs -if reeds.io.hpc: +if reeds.slurm.check_slurm(): remotepath = '/kfs2/shared-projects/reeds' filepaths = { 'land': os.path.join( diff --git a/reeds/io.py b/reeds/io.py index 90b3b0c99..02084ae35 100644 --- a/reeds/io.py +++ b/reeds/io.py @@ -21,7 +21,6 @@ if 'runs' in reeds_path.split(os.path.sep): reeds_path = reeds_path[: reeds_path.index(os.sep + 'runs' + os.sep)] -hpc = reeds.slurm.check_slurm() # ######## ######## ### ######## # ## ## ## ## ## ## ## From 147cd67f91e5bde1fc8a28354937a5329a0e89a5 Mon Sep 17 00:00:00 2001 From: Patrick Brown <25125211+patrickbrown4@users.noreply.github.com> Date: Tue, 20 Oct 2026 17:53:32 -0600 Subject: [PATCH 3/5] bump geopandas to 1.2 --- environment.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/environment.yml b/environment.yml index bbe8d8b05..aa988c008 100644 --- a/environment.yml +++ b/environment.yml @@ -8,7 +8,7 @@ dependencies: - bokeh=3.9 - click=8.4 - cmocean=4.0 - - geopandas=1.1 + - geopandas=1.2 - git-lfs=3.7 - gitpython=3.1 - h5py=3.16 From b3aeff1d0932e229c1f2a966ab47fd6a6d5dd951 Mon Sep 17 00:00:00 2001 From: Patrick Brown <25125211+patrickbrown4@users.noreply.github.com> Date: Tue, 20 Oct 2026 18:29:39 -0600 Subject: [PATCH 4/5] runreeds.py: remove unnecessary bash steps --- runreeds.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/runreeds.py b/runreeds.py index 41f4bd7f9..716255850 100644 --- a/runreeds.py +++ b/runreeds.py @@ -1282,13 +1282,12 @@ def write_batch_script( comment('Set up nodal environment for run', OPATH) OPATH.writelines(". $HOME/.bashrc \n") OPATH.writelines("module purge \n") - OPATH.writelines("source /nopt/nrel/apps/env.sh \n") OPATH.writelines("module load anaconda3 \n") OPATH.writelines("module use /nopt/nrel/apps/software/gams/modulefiles \n") OPATH.writelines("module load gams \n") OPATH.writelines("module load julia/1.12.1 \n") OPATH.writelines("conda activate reeds \n") - OPATH.writelines('export R_LIBS_USER="$HOME/rlib" \n\n\n') + OPATH.writelines('\n\n') #%% Write the input_processing script calls big_comment('Input processing', OPATH) From a84a7e95063a0623350547e7b3171a3218e548b2 Mon Sep 17 00:00:00 2001 From: Patrick Brown <25125211+patrickbrown4@users.noreply.github.com> Date: Tue, 20 Oct 2026 20:11:30 -0600 Subject: [PATCH 5/5] remove need for REEDS_USE_SLURM environment variable --- reeds/slurm.py | 5 +---- runreeds.py | 10 ++-------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/reeds/slurm.py b/reeds/slurm.py index add85dfe0..07e03deb5 100644 --- a/reeds/slurm.py +++ b/reeds/slurm.py @@ -22,8 +22,5 @@ def check_slurm(forcelocal=False): if forcelocal: hpc = False else: - if os.environ.get('REEDS_USE_SLURM') and get_cluster(): - hpc = True - else: - hpc = False + hpc = True if get_cluster() else False return hpc diff --git a/runreeds.py b/runreeds.py index 716255850..34ed0ed3d 100644 --- a/runreeds.py +++ b/runreeds.py @@ -838,14 +838,8 @@ def setupEnvironment( ### If on NLR HPC but NOT submitting slurm job, ask for confirmation if reeds.slurm.get_cluster() and (not hpc): print( - "It looks like you're running on the NLR HPC but the REEDS_USE_SLURM environment " - "variable is not set to 1, meaning the model will run locally rather than being " - "submitted as a slurm job. Are you sure you want to run locally? " - "If not:\n" - " Add `export REEDS_USE_SLURM=1` to your ~/.bashrc file\n" - " Run `source ~/.bashrc`\n" - " Run `conda activate reeds` to reactivate the environment\n" - " Rerun this script" + "It looks like you're running on the HPC login node instead of submitting a " + "slurm job. Are you sure you want to run locally (not recommended)?" ) confirm_local = str(input('Run job locally? y/[n]: ') or 'n') if confirm_local not in ['y','Y','yes','Yes','YES']: