diff --git a/e3sm_supported_machines/create_new_e3sm_unified_env.bash b/e3sm_supported_machines/create_new_e3sm_unified_env.bash deleted file mode 100755 index 5d377aa..0000000 --- a/e3sm_supported_machines/create_new_e3sm_unified_env.bash +++ /dev/null @@ -1,279 +0,0 @@ -#!/bin/bash - -check_env () { - echo "Checking the environment $env_name" - export CDAT_ANONYMOUS_LOG=no - - if python -c "import vcs"; then - echo " vcs passed" - else - echo " vcs failed" - exit 1 - fi - if python -c "import ILAMB"; then - echo " ILAMB passed" - else - echo " ILAMB failed" - exit 1 - fi - if python -c "import acme_diags"; then - echo " import acme_diags passed" - else - echo " import acme_diags failed" - exit 1 - fi - - if e3sm_diags --help; then - echo " e3sm_diags passed" - else - echo " e3sm_diags failed" - exit 1 - fi - - if python -c "import mpas_analysis"; then - echo " import mpas_analysis passed" - else - echo " import mpas_analysis failed" - exit 1 - fi - - if mpas_analysis -h; then - echo " mpas_analysis passed" - else - echo " mpas_analysis failed" - exit 1 - fi - - if python -c "import livvkit"; then - echo " livvkit passed" - else - echo " livvkit failed" - exit 1 - fi - - if livv --version; then - echo " livv passed" - else - echo " livv failed" - exit 1 - fi - - if python -c "import IPython"; then - echo " IPython passed" - else - echo " IPython failed" - exit 1 - fi - - if python -c "import globus_cli"; then - echo " globus_cli passed" - else - echo " globus_cli failed" - exit 1 - fi - - if globus --help; then - echo " globus passed" - else - echo " globus failed" - exit 1 - fi - - if python -c "import zstash"; then - echo " import zstash passed" - else - echo " import zstash failed" - exit 1 - fi - - if zstash --help; then - echo " zstash passed" - else - echo " zstash failed" - exit 1 - fi - - if zstash --help; then - echo " zstash passed" - else - echo " zstash failed" - exit 1 - fi - - if GenerateCSMesh --res 64 --alt --file gravitySam.000000.3d.cubedSphere.g; then - echo " tempest-remap passed" - else - echo " tempest-remap failed" - exit 1 - fi - if processflow -v; then - echo " processflow passed" - else - echo " processflow failed" - exit 1 - fi - -} - - -# Modify the following to choose which e3sm-unified version(s) the python version(s) are installed and whether to make -# an environment with x-windows support under cdat (cdatx) and/or without (nox). Typically, both environments should -# be created. -versions=(1.3.1) -pythons=(3.7) -env_types=(nox cdatx) - -default_python=3.7 -default_env_type=nox - -# Any subsequent commands which fail will cause the shell script to exit -# immediately -set -e -# The rest of the script should not need to be modified -if [[ $HOSTNAME = "cori"* ]] || [[ $HOSTNAME = "dtn"* ]]; then - base_path="/global/cfs/cdirs/e3sm/software/anaconda_envs/base" - activ_path="/global/cfs/cdirs/e3sm/software/anaconda_envs" - group="e3sm" - module unload PrgEnv-intel - module load PrgEnv-gnu - module unload craype-hugepages2M - custom_script="echo module unlaod PrgEnv-intel" - custom_script="${custom_script}"$'\n'"module unload PrgEnv-intel" - custom_script="${custom_script}"$'\n'"echo module load PrgEnv-gnu" - custom_script="${custom_script}"$'\n'"module laod PrgEnv-gnu" - custom_script="${custom_script}"$'\n'"echo module unload craype-hugepages2M" - custom_script="${custom_script}"$'\n'"module unload craype-hugepages2M" - mpicc="$(which cc) -shared" - mpi="nompi" -elif [[ $HOSTNAME = "acme1"* ]] || [[ $HOSTNAME = "aims4"* ]]; then - base_path="/usr/local/e3sm_unified/envs/base" - activ_path="/usr/local/e3sm_unified/envs" - group="climate" - mpi="mpich" -elif [[ $HOSTNAME = "blueslogin"* ]]; then - base_path="/lcrc/soft/climate/e3sm-unified/base" - activ_path="/lcrc/soft/climate/e3sm-unified" - group="climate" - mpi="mpich" -elif [[ $HOSTNAME = "rhea"* ]]; then - base_path="/ccs/proj/cli900/sw/rhea/e3sm-unified/base" - activ_path="/ccs/proj/cli900/sw/rhea/e3sm-unified" - group="cli900" - mpi="nompi" -elif [[ $HOSTNAME = "cooley"* ]]; then - base_path="/lus/theta-fs0/projects/ccsm/acme/tools/e3sm-unified/base" - activ_path="/lus/theta-fs0/projects/ccsm/acme/tools/e3sm-unified" - group="ccsm" - mpi="nompi" -elif [[ $HOSTNAME = "compy"* ]]; then - base_path="/share/apps/E3SM/conda_envs/base" - activ_path="/share/apps/E3SM/conda_envs" - group="users" - mpi="mpich" -elif [[ $HOSTNAME = "gr-fe"* ]] || [[ $HOSTNAME = "wf-fe"* ]]; then - base_path="/usr/projects/climate/SHARED_CLIMATE/anaconda_envs/base" - activ_path="/usr/projects/climate/SHARED_CLIMATE/anaconda_envs" - group="climate" - mpi="mpich" -elif [[ $HOSTNAME = "burnham"* ]]; then - base_path="/home/xylar/Desktop/test_e3sm_unified/base" - activ_path="/home/xylar/Desktop/test_e3sm_unified" - group="xylar" - mpi="mpich" -else - echo "Unknown host name $HOSTNAME. Add env_path and group for this machine to the script." - exit 1 -fi - -if [ ! -d $base_path ]; then - miniconda=Miniconda3-latest-Linux-x86_64.sh - wget https://repo.continuum.io/miniconda/$miniconda - /bin/bash $miniconda -b -p $base_path - rm $miniconda -fi - -# activate the new environment -source ${base_path}/etc/profile.d/conda.sh -conda activate - -conda config --add channels conda-forge -conda config --set channel_priority strict -conda update -y --all - -for version in "${versions[@]}" -do - for python in "${pythons[@]}" - do - for env_type in "${env_types[@]}" - do - if [ "$env_type" == "nox" ]; then - channels="--override-channels -c conda-forge -c defaults -c e3sm -c cdat/label/v82" - packages="python=$python e3sm-unified=${version}=mpi_${mpi}* mesalib" - else - channels="--override-channels -c conda-forge -c defaults -c e3sm -c cdat/label/v82" - packages="python=$python e3sm-unified=${version}=mpi_${mpi}*" - fi - - if [[ "$python" == "$default_python" && "$env_type" == "$default_env_type" ]]; then - suffix="" - elif [[ "$python" == "$default_python" ]]; then - suffix="_${env_type}" - else - suffix="_py${python}_${env_type}" - fi - - env_name=e3sm_unified_${version}${suffix} - if [ ! -d "$base_path/envs/$env_name" ]; then - echo creating "$env_name" - conda create -n "$env_name" -y $channels $packages - conda activate "$env_name" - conda deactivate - else - echo "$env_name" already exists - fi - - conda activate "$env_name" - check_env - conda deactivate - - mkdir -p "$activ_path" - - # make activation scripts - for ext in sh csh - do - script="" - if [[ $ext = "sh" ]]; then - script="${script}"$'\n'"if [ -x \"\$(command -v module)\" ] ; then" - script="${script}"$'\n'" module unload python" - script="${script}"$'\n'"fi" - fi - script="${script}"$'\n'"source ${base_path}/etc/profile.d/conda.${ext}" - script="${script}"$'\n'"conda activate $env_name" - file_name=$activ_path/load_latest_e3sm_unified${suffix}.${ext} - rm -f "$file_name" - echo "${script}" > "$file_name" - done - done - done -done - -# delete the tarballs and any unused packages -conda clean -y -p -t - -# continue if errors happen from here on -set +e - -echo "changing permissions on activation scripts" -chown "$USER":$group $activ_path/load_latest_e3sm_unified* -chmod go+r,go-w $activ_path/load_latest_e3sm_unified* - -echo "changing permissions on environments" -cd $base_path -echo " changing directory permissions" -find $base_path -user $USER -type d -exec chgrp $group "{}" \; \ - -exec chmod u=rwx,go=rx "{}" \; -echo " changing file permissions" -find $base_path -user $USER -type f -exec chgrp $group "{}" \; \ - -exec chmod u+rw,go+r,go-w "{}" \; -echo " done." - diff --git a/e3sm_supported_machines/create_new_e3sm_unified_env.py b/e3sm_supported_machines/create_new_e3sm_unified_env.py new file mode 100755 index 0000000..d577d16 --- /dev/null +++ b/e3sm_supported_machines/create_new_e3sm_unified_env.py @@ -0,0 +1,270 @@ +#!/usr/bin/env python +import subprocess +import os +import socket +import glob +import stat +import pwd +import grp +import requests +import progressbar + + +def check_env(base_path, env_name): + print("Checking the environment {}".format(env_name)) + env = os.environ + env['CDAT_ANONYMOUS_LOG'] = 'no' + + activate = 'source {}/etc/profile.d/conda.sh; conda activate {}'.format( + base_path, env_name) + + imports = ['vcs', 'ILAMB', 'acme_diags', 'mpas_analysis', 'livvkit', + 'IPython', 'globus_cli', 'zstash'] + for import_name in imports: + command = '{}; python -c "import {}"'.format(activate, import_name) + try: + subprocess.check_call(command, env=env, executable='/bin/bash', + shell=True) + except subprocess.CalledProcessError as e: + print(' {} failed'.format(import_name)) + raise e + print(' {} passes'.format(import_name)) + + commands = [['e3sm_diags', '--help'], + ['mpas_analysis', '-h'], + ['livv', '--version'], + ['globus', '--help'], + ['zstash', '--help'], + ['processflow', '-v']] + + for command in commands: + exec = command[0] + command = '{}; {}'.format(activate, ' '.join(command)) + try: + subprocess.check_call(command, env=env, executable='/bin/bash', + shell=True, stdout=subprocess.DEVNULL) + except subprocess.CalledProcessError as e: + print(' {} failed'.format(exec)) + raise e + print(' {} passes'.format(exec)) + + package = 'tempest-remap' + command = '{}; GenerateCSMesh --res 64 --alt --file ' \ + 'gravitySam.000000.3d.cubedSphere.g'.format(activate) + try: + subprocess.check_call(command, env=env, executable='/bin/bash', + shell=True, stdout=subprocess.DEVNULL) + except subprocess.CalledProcessError as e: + print(' {} failed'.format(package)) + raise e + print(' {} passes'.format(package)) + + +def get_host_info(): + hostname = socket.gethostname() + if hostname.startswith('cori') or hostname.startswith('dtn'): + base_path = "/global/cfs/cdirs/e3sm/software/anaconda_envs/base" + activ_path = "/global/cfs/cdirs/e3sm/software/anaconda_envs" + group = "e3sm" + elif hostname.startswith('acme1') or hostname.startswith('aims4'): + base_path = "/usr/local/e3sm_unified/envs/base" + activ_path = "/usr/local/e3sm_unified/envs" + group = "climate" + elif hostname.startswith('blueslogin'): + base_path = "/lcrc/soft/climate/e3sm-unified/base" + activ_path = "/lcrc/soft/climate/e3sm-unified" + group = "climate" + elif hostname.startswith('rhea'): + base_path = "/ccs/proj/cli900/sw/rhea/e3sm-unified/base" + activ_path = "/ccs/proj/cli900/sw/rhea/e3sm-unified" + group = "cli900" + elif hostname.startswith('cooley'): + base_path = "/lus/theta-fs0/projects/ccsm/acme/tools/e3sm-unified/base" + activ_path = "/lus/theta-fs0/projects/ccsm/acme/tools/e3sm-unified" + group = "ccsm" + elif hostname.startswith('compy'): + base_path = "/share/apps/E3SM/conda_envs/base" + activ_path = "/share/apps/E3SM/conda_envs" + group = "users" + elif hostname.startswith('gr-fe') or hostname.startswith('wf-fe'): + base_path = "/usr/projects/climate/SHARED_CLIMATE/anaconda_envs/base" + activ_path = "/usr/projects/climate/SHARED_CLIMATE/anaconda_envs" + group = "climate" + elif hostname.startswith('burnham'): + base_path = "/home/xylar/Desktop/test_e3sm_unified/base" + activ_path = "/home/xylar/Desktop/test_e3sm_unified" + group = "xylar" + else: + raise ValueError("Unknown host name {}. Add env_path and group for " + "this machine to the script.".format(hostname)) + + return base_path, activ_path, group + + +def main(): + # Modify the following list of dictionaries to choose which e3sm-unified + # version, python version, whether to make an environment with + # x-windows support under cdat (cdatx) and/or without (nox), and which mpi + # variant (nompi, mpich or openmpi) to use. + + envs = [{'suffix': '', + 'version': '1.3.1', + 'python': '3.7', + 'env_type': 'nox', + 'mpi': 'nompi'}, + {'suffix': '_cdatx', + 'version': '1.3.1', + 'python': '3.7', + 'env_type': 'cdatx', + 'mpi': 'nompi'}, + {'suffix': '_mpich', + 'version': '1.3.1', + 'python': '3.7', + 'env_type': 'nox', + 'mpi': 'mpich'}] + + base_path, activ_path, group = get_host_info() + + if not os.path.exists(base_path): + miniconda = 'Miniconda3-latest-Linux-x86_64.sh' + url = 'https://repo.continuum.io/miniconda/{}'.format(miniconda) + r = requests.get(url) + with open(miniconda, 'wb') as outfile: + outfile.write(r.content) + + command = '/bin/bash {} -b -p {}'.format(miniconda, base_path) + subprocess.check_call(command, executable='/bin/bash', shell=True) + os.remove(miniconda) + + print('Doing initial setup') + activate = 'source {}/etc/profile.d/conda.sh; conda activate'.format( + base_path) + + commands = '{}; conda config --add channels conda-forge; ' \ + 'conda config --set channel_priority strict; ' \ + 'conda update -y --all'.format(activate) + + subprocess.check_call(commands, executable='/bin/bash', shell=True) + print('done') + + for env in envs: + version = env['version'] + suffix = env['suffix'] + python = env['python'] + env_type = env['env_type'] + mpi = env['mpi'] + if mpi == 'nompi': + mpi_prefix = 'nompi' + else: + mpi_prefix = 'mpi_{}'.format(mpi) + + channels = '--override-channels -c conda-forge -c defaults ' \ + '-c e3sm -c cdat/label/v82' + packages = 'python={} "e3sm-unified={}={}_*"'.format( + python, version, mpi_prefix) + if env_type == 'nox': + packages = '{} mesalib'.format(packages) + + env_name = 'e3sm_unified_{}{}'.format(version, suffix) + if not os.path.exists('{}/envs/{}'.format(base_path, env_name)): + print('creating {}'.format(env_name)) + commands = '{}; conda create -y -n {} {} {}'.format( + activate, env_name, channels, packages) + subprocess.check_call(commands, executable='/bin/bash', shell=True) + else: + print('{} already exists'.format(env_name)) + + check_env(base_path, env_name) + + try: + os.makedirs(activ_path) + except FileExistsError: + pass + + for ext in ['sh', 'csh']: + script = [] + if ext == 'sh': + script.extend(['if [ -x "$(command -v module)" ] ; then\n', + ' module unload python\n', + 'fi\n']) + script.append('source {}/etc/profile.d/conda.{}\n'.format( + base_path, ext)) + script.append('conda activate {}\n'.format(env_name)) + + file_name = '{}/load_latest_e3sm_unified{}.{}'.format( + activ_path, suffix, ext) + if os.path.exists(file_name): + os.remove(file_name) + with open(file_name, 'w') as f: + f.writelines(script) + + commands = '{}; conda clean -y -p -t'.format(activate) + subprocess.check_call(commands, executable='/bin/bash', shell=True) + + print('changing permissions on activation scripts') + activation_files = glob.glob('{}/load_latest_e3sm_unified*'.format( + activ_path)) + + read_perm = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH + exec_perm = (stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | + stat.S_IRGRP | stat.S_IXGRP | + stat.S_IROTH | stat.S_IXOTH) + + for file_name in activation_files: + os.chmod(file_name, read_perm) + + print('changing permissions on environments') + + uid = os.getuid() + gid = grp.getgrnam(group).gr_gid + + files_and_dirs = [] + for root, dirs, files in os.walk(base_path): + files_and_dirs.extend(dirs) + files_and_dirs.extend(files) + + widgets = [progressbar.Percentage(), ' ', progressbar.Bar(), + ' ', progressbar.ETA()] + bar = progressbar.ProgressBar(widgets=widgets, + maxval=len(files_and_dirs)).start() + progress = 0 + for root, dirs, files in os.walk(base_path): + for directory in dirs: + progress += 1 + bar.update(progress) + + directory = os.path.join(root, directory) + try: + os.chown(directory, uid, gid) + os.chmod(directory, exec_perm) + except OSError: + continue + + + for file_name in files: + progress += 1 + bar.update(progress) + file_name = os.path.join(root, file_name) + try: + perm = os.stat(file_name).st_mode + except OSError: + continue + + if perm & stat.S_IXUSR: + # executable, so make sure others can execute it + perm = exec_perm + else: + perm = read_perm + + try: + os.chown(file_name, uid, gid) + os.chmod(file_name, perm) + except OSError: + continue + + bar.finish() + print(' done.') + + +if __name__ == '__main__': + main()