├── .github └── workflows │ └── CI.yml ├── .gitignore ├── .gitmodules ├── MOM_diags.txt ├── README.md ├── accessom.yml ├── doc └── static │ └── ACCESSOM2_System_Architecture.png ├── hashexe-public.sh ├── hashexe.sh ├── install.sh ├── libcheck.sh ├── test ├── checksums │ ├── 1deg_jra55_iaf-access-om2.out │ ├── cm_1440x1080-test.txt │ ├── cm_360x300-test.txt │ └── om_1440x1080-test.txt ├── dump_field.F90 ├── exp_test_helper.py ├── load_dump.py ├── requirements_test.txt ├── test_bit_reproducibility.py ├── test_build.py ├── test_coupling_fields.py ├── test_grids_match.py ├── test_remapping_weights.py ├── test_run.py ├── test_startup.py ├── test_valgrind.py ├── util.py └── valgrind_suppressions.txt └── tools ├── .pylintrc ├── README.md ├── add_core2_time_bounds.py ├── calc_input_checksum.py ├── contrib ├── build_esmf_on_raijin.sh └── build_esmf_on_ubuntu.sh ├── make_cice_grid.py ├── make_remap_weights.py ├── make_remap_weights.sh ├── make_salt_sfc_restore.py └── release.py /.github/workflows/CI.yml: -------------------------------------------------------------------------------- 1 | # Run CI tests 2 | name: CI 3 | 4 | # Controls when the action will run. 5 | on: 6 | # Triggers the workflow on push or pull request events but only for the master branch 7 | push: 8 | branches: [ master ] 9 | pull_request: 10 | branches: [ master ] 11 | 12 | # Allows you to run this workflow manually from the Actions tab 13 | workflow_dispatch: 14 | 15 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 16 | jobs: 17 | build: 18 | runs-on: ubuntu-latest 19 | 20 | # Run the job for different versions of python 21 | strategy: 22 | matrix: 23 | python-version: [3.7, 3.8, 3.9] 24 | 25 | # Steps represent a sequence of tasks that will be executed as part of the job 26 | steps: 27 | 28 | # Checks-out repository code 29 | - name: Checkout code 30 | uses: actions/checkout@v2 31 | with: 32 | submodules: recursive 33 | 34 | - name: Set up Python ${{ matrix.python-version }} 35 | uses: actions/setup-python@v2 36 | with: 37 | python-version: ${{ matrix.python-version }} 38 | 39 | - name: Install dependencies 40 | run: pip install -r test/requirements_test.txt 41 | 42 | - name: Lint test 43 | working-directory: ./test 44 | run: pylint --extension-pkg-whitelist=netCDF4 --errors-only --ignore=test_coupling_fields.py,test_grids_match.py,test_valgrind.py *.py 45 | 46 | - name: Lint tools 47 | working-directory: ./tools 48 | run: pylint --extension-pkg-whitelist=netCDF4 -v --errors-only --rcfile=.pylintrc *.py 49 | 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # 2 | 3 | archive 4 | bin 5 | work 6 | access-om2.err 7 | access-om2.out 8 | pbs_logs 9 | 10 | tools/PET* 11 | tools/*.nc 12 | tools/contrib/esmf 13 | tools/contrib/bin 14 | 15 | *.swp 16 | input_*.tar.gz 17 | input 18 | 19 | .cache 20 | 21 | # Byte-compiled / optimized / DLL files 22 | __pycache__/ 23 | *.py[cod] 24 | 25 | # C extensions 26 | *.so 27 | 28 | payu-experiments 29 | 30 | ._* 31 | 32 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/mom"] 2 | path = src/mom 3 | url = https://github.com/mom-ocean/MOM5.git 4 | [submodule "src/cice5"] 5 | path = src/cice5 6 | url = https://github.com/COSIMA/cice5.git 7 | [submodule "control/1deg_jra55_ryf"] 8 | path = control/1deg_jra55_ryf 9 | url = https://github.com/COSIMA/1deg_jra55_ryf.git 10 | [submodule "control/01deg_jra55_ryf"] 11 | path = control/01deg_jra55_ryf 12 | url = https://github.com/COSIMA/01deg_jra55_ryf.git 13 | [submodule "control/025deg_jra55_ryf"] 14 | path = control/025deg_jra55_ryf 15 | url = https://github.com/COSIMA/025deg_jra55_ryf.git 16 | [submodule "tools/esmgrids"] 17 | path = tools/esmgrids 18 | url = https://github.com/DoublePrecision/esmgrids.git 19 | [submodule "src/libaccessom2"] 20 | path = src/libaccessom2 21 | url = https://github.com/COSIMA/libaccessom2.git 22 | [submodule "control/1deg_jra55_iaf"] 23 | path = control/1deg_jra55_iaf 24 | url = https://github.com/COSIMA/1deg_jra55_iaf.git 25 | [submodule "control/01deg_jra55_iaf"] 26 | path = control/01deg_jra55_iaf 27 | url = https://github.com/COSIMA/01deg_jra55_iaf.git 28 | [submodule "control/025deg_jra55_iaf"] 29 | path = control/025deg_jra55_iaf 30 | url = https://github.com/COSIMA/025deg_jra55_iaf.git 31 | [submodule "tools/initial_conditions_access-om2"] 32 | path = tools/initial_conditions_access-om2 33 | url = https://github.com/COSIMA/initial_conditions_access-om2.git 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 |

3 | 4 | ---------- 5 | # _DEPRECATION NOTICE_ 6 | 7 | _[ACCESS-NRI](https://www.access-nri.org.au/) has taken on responsibility for ongoing support of ACCESS-OM2, so this repository is not being updated and will eventually be archived._ 8 | 9 | _**New ACCESS-OM2 experiments and code development should use the latest code release from [ACCESS-NRI/ACCESS-OM2](https://github.com/ACCESS-NRI/ACCESS-OM2) and configurations from [ACCESS-NRI/access-om2-configs](https://github.com/ACCESS-NRI/access-om2-configs), and all new issues should be posted on one of those repositories.**_ 10 | 11 | ----------- 12 | 13 | # ACCESS-OM2 14 | 15 | ACCESS-OM2 is a global coupled ocean - sea ice model being developed by [COSIMA](http://www.cosima.org.au). 16 | 17 | ACCESS-OM2 consists of the [MOM 5.1](https://mom-ocean.github.io) ocean model, [CICE 5.1.2](https://github.com/CICE-Consortium/CICE-svn-trunk/tree/cice-5.1.2) sea ice model, and a file-based atmosphere called [YATM](https://github.com/COSIMA/libaccessom2) coupled together using [OASIS3-MCT v2.0](https://portal.enes.org/oasis). ACCESS-OM2 builds on the ACCESS-OM ([Bi et al., 2013](http://www.bom.gov.au/jshess/docs/2013/bi2_hres.pdf)) and AusCOM ([Roberts et al., 2007](https://50years.acs.org.au/content/dam/acs/50-years/journals/jrpit/JRPIT39.2.137.pdf); [Bi and Marsland, 2010](https://www.cawcr.gov.au/technical-reports/CTR_027.pdf)) models originally developed at [CSIRO](http://www.csiro.au). 18 | 19 | ACCESS-OM2 comes with a number of standard configurations in the [control](https://github.com/COSIMA/access-om2/tree/master/control) directory. These include sea ice and ocean at a nominal 1.0, 0.25 and 0.1 degree horizontal grid spacing, forced by [JRA55-do](https://doi.org/10.1016/j.ocemod.2018.07.002) atmospheric reanalyses. 20 | 21 | ACCESS-OM2 is being used for a growing number of research projects. A partial list of publications using the model is given [here](https://scholar.google.com/citations?hl=en&view_op=list_works&gmla=AJsN-F5gp3-wpXzF8odo9cFy-9ajlgIeqwrOq_7DvPS1rkETzqmPk1Sfx-gAmIs9kFfRflOR3HqNV_85pJ2j4LljHks1wQtONqiuOVgii-UICb9q2fmTp_w&user=inVqu_4AAAAJ). 22 | 23 | # Downloading 24 | 25 | This repository contains many submodules, so you will need to clone it with the `--recursive` flag: 26 | ``` 27 | git clone --recursive https://github.com/COSIMA/access-om2.git 28 | ``` 29 | 30 | To update a previous clone of this repository to the latest version, you will need to do 31 | ``` 32 | git pull 33 | ``` 34 | followed by 35 | ``` 36 | git submodule update --init --recursive 37 | ``` 38 | to update all the submodules. 39 | 40 | # Where to find information 41 | 42 | The v1.0 model code, configurations and performance were described in [Kiss et al. (2020)](https://doi.org/10.5194/gmd-13-401-2020), with further details in the draft [ACCESS-OM2 technical report](https://github.com/COSIMA/ACCESS-OM2-1-025-010deg-report). The current code and configurations differ from v1.0 in a number of ways (biogeochemistry, updated forcing, improvements and bug fixes), as described by [Solodoch et al. (2022)](https://doi.org/10.1029/2021GL097211), [Hayashida et al. (2023)](https://dx.doi.org/10.1029/2023JC019697), [Menviel et al. (2023)](https://doi.org/10.5194/egusphere-2023-390) and [Wang et al. (2023)](https://doi.org/10.5194/gmd-2023-123). 43 | 44 | Model output can be accessed by [NCI](http://nci.org.au) users via the [COSIMA Cookbook](https://github.com/COSIMA/cosima-cookbook). 45 | 46 | For information on downloading, building and running the model, see the [ACCESS-OM2 wiki](https://github.com/COSIMA/access-om2/wiki). 47 | 48 | **NOTE:** All ACCESS-OM2 model components and configurations are undergoing continual improvement. We strongly recommend that you "watch" this repo (see button at top of screen; ask to be notified of all conversations) and also watch all the [component models](https://github.com/COSIMA/access-om2/tree/master/src), whichever [configuration(s)](https://github.com/COSIMA/access-om2/tree/master/control) you are using, and [`payu`](https://github.com/payu-org/payu) to be kept informed of updates, problems and bug fixes as they arise. 49 | 50 | Requests for help and other issues associated with the model, tools or configurations can be registered as [ACCESS-OM2 issues](https://github.com/COSIMA/access-om2/issues). 51 | 52 | ## Conditions of use 53 | 54 | We request that users of this or other ACCESS-OM2 model code: 55 | 1. consider citing Kiss et al. (2020) ([http://doi.org/10.5194/gmd-13-401-2020](http://doi.org/10.5194/gmd-13-401-2020)), and also the other [papers above](https://github.com/COSIMA/access-om2#where-to-find-information) detailing more recent improvements to the model 56 | 2. include an acknowledgement such as the following: 57 | 58 | *The authors thank the Consortium for Ocean-Sea Ice Modelling in Australia (COSIMA; [http://www.cosima.org.au](http://www.cosima.org.au)) for making the ACCESS-OM2 suite of models available at [https://github.com/COSIMA/access-om2](https://github.com/COSIMA/access-om2).* 59 | 3. let us know of any publications which use these models or data so we can add them to [our list](https://scholar.google.com/citations?hl=en&user=inVqu_4AAAAJ). 60 | -------------------------------------------------------------------------------- /accessom.yml: -------------------------------------------------------------------------------- 1 | name: accessom 2 | channels: 3 | - conda-forge 4 | - defaults 5 | dependencies: 6 | - asn1crypto=0.22.0=py36_0 7 | - cffi=1.11.2=py36_0 8 | - chardet=3.0.4=py36_0 9 | - ckanapi=4.1=py_0 10 | - cryptography=2.0.3=py36_0 11 | - docopt=0.6.2=py36_0 12 | - idna=2.6=py36_1 13 | - pycparser=2.18=py36_0 14 | - pyopenssl=17.4.0=py36_0 15 | - pysocks=1.6.7=py36_0 16 | - requests=2.18.4=py36_1 17 | - simplejson=3.11.1=py36_0 18 | - six=1.11.0=py36_1 19 | - urllib3=1.22=py36_0 20 | - ca-certificates=2017.08.26=h1d4fec5_0 21 | - certifi=2017.11.5=py36hf29ccca_0 22 | - libedit=3.1=heed3624_0 23 | - libffi=3.2.1=hd88cf55_4 24 | - libgcc-ng=7.2.0=h7cc24e2_2 25 | - libstdcxx-ng=7.2.0=h7a57d05_2 26 | - ncurses=6.0=h9df7e31_2 27 | - openssl=1.0.2m=h26d622b_1 28 | - pip=9.0.1=py36h6c6f9ce_4 29 | - python=3.6.3=h6c0c0dc_5 30 | - readline=7.0=ha6073c6_4 31 | - setuptools=36.5.0=py36he42e2e1_0 32 | - sqlite=3.20.1=hb898158_2 33 | - tk=8.6.7=hc745277_3 34 | - wheel=0.30.0=py36hfd4bba0_1 35 | - xz=5.2.3=h55aa19d_2 36 | - zlib=1.2.11=ha838bed_2 37 | - pip: 38 | - apipkg==1.4 39 | - attrs==17.3.0 40 | - execnet==1.5.0 41 | - llvmlite==0.20.0 42 | - netcdf4==1.3.1 43 | - nose==1.3.7 44 | - numba==0.35.0 45 | - numpy==1.13.3 46 | - pep8==1.7.1 47 | - pluggy==0.6.0 48 | - py==1.5.2 49 | - pyproj==1.9.5.1 50 | - pytest==3.3.0 51 | - pytest-cache==1.0 52 | - pytest-pep8==1.0.6 53 | - pyyaml==3.12 54 | - scipy==1.0.0 55 | - sh==1.12.14 56 | - shapely==1.6.2.post1 57 | prefix: /short/ir04/ap4626/anaconda3/envs/accessom 58 | 59 | -------------------------------------------------------------------------------- /doc/static/ACCESSOM2_System_Architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSIMA/access-om2/c35ebfaaaf287041b42998f1a9a40191cef9b79b/doc/static/ACCESSOM2_System_Architecture.png -------------------------------------------------------------------------------- /hashexe-public.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Copy ACCESS-OM2 executables to bin with githash in name, and config.yaml to match. 4 | # All changes to config.yaml are reported. 5 | # This is basically the same as hashexe.sh but copies to a public bin dir (using non-clobbering copy for safety). 6 | # 7 | # Andrew Kiss https://github.com/aekiss 8 | 9 | set -e 10 | 11 | if [[ -z "${ACCESS_OM_DIR}" ]]; then 12 | export ACCESS_OM_DIR=$(pwd) 13 | fi 14 | 15 | if [[ -z "${public}" ]]; then 16 | public=/g/data/ik11/inputs/access-om2/bin # if not called from update-commit-push.sh 17 | fi 18 | 19 | if [ -w $public ]; then 20 | bindir=$public 21 | else 22 | echo "You don't have write access to $public. Exiting." 23 | exit 1 24 | fi 25 | 26 | if [[ -z "${mom_type}" ]]; then 27 | echo "FATAL ERROR: mom_type not set. Need to do whichever of these is appropriate" 28 | echo " export mom_type=ACCESS-OM" 29 | echo "or" 30 | echo " export mom_type=ACCESS-OM-BGC" 31 | echo "taking into account the branches the control dirs are on:" 32 | for d in control/*; do cd $d; echo $d; git status | grep "On branch"; cd -; done 33 | exit 1 34 | fi 35 | 36 | yatmpath=${ACCESS_OM_DIR}/src/libaccessom2/build/bin/yatm.exe 37 | fmspath=${ACCESS_OM_DIR}/src/mom/exec/nci/${mom_type}/fms_${mom_type}.x 38 | cice1path=${ACCESS_OM_DIR}/src/cice5/build_auscom_360x300_24p/cice_auscom_360x300_24p.exe 39 | cice025path=${ACCESS_OM_DIR}/src/cice5/build_auscom_1440x1080_480p/cice_auscom_1440x1080_480p.exe 40 | cice010path=${ACCESS_OM_DIR}/src/cice5/build_auscom_3600x2700_722p/cice_auscom_3600x2700_722p.exe 41 | cice010path_18x15=${ACCESS_OM_DIR}/src/cice5/build_auscom_18x15.3600x2700_1682p/cice_auscom_18x15.3600x2700_1682p.exe 42 | mppnccombinepath=${ACCESS_OM_DIR}/src/mom/bin/mppnccombine.nci 43 | 44 | config1ryfpath=${ACCESS_OM_DIR}/control/1deg_jra55_ryf/config.yaml 45 | config025ryfpath=${ACCESS_OM_DIR}/control/025deg_jra55_ryf/config.yaml 46 | config010ryfpath=${ACCESS_OM_DIR}/control/01deg_jra55_ryf/config.yaml 47 | 48 | config1iafpath=${ACCESS_OM_DIR}/control/1deg_jra55_iaf/config.yaml 49 | config025iafpath=${ACCESS_OM_DIR}/control/025deg_jra55_iaf/config.yaml 50 | config010iafpath=${ACCESS_OM_DIR}/control/01deg_jra55_iaf/config.yaml 51 | 52 | echo "Getting executable hashes..." 53 | 54 | cd $(dirname "${yatmpath}") && yatmhash=`git rev-parse --short=7 HEAD` 55 | test -z "$(git status --porcelain)" || yatmhash=${yatmhash}-modified # uncommitted changes or untracked files 56 | cd $(dirname "${fmspath}") && fmshash=`git rev-parse --short=7 HEAD` 57 | test -z "$(git status --porcelain)" || fmshash=${fmshash}-modified # uncommitted changes or untracked files 58 | fmshash=${fmshash}_libaccessom2_${yatmhash} # also track libaccessom2 59 | cd $(dirname "${cice1path}") && cicehash=`git rev-parse --short=7 HEAD` # NB only one hash for all three cice builds 60 | test -z "$(git status --porcelain)" || cicehash=${cicehash}-modified # uncommitted changes or untracked files 61 | cicehash=${cicehash}_libaccessom2_${yatmhash} # also track libaccessom2 62 | 63 | echo "Copying executables to "${bindir}" with hashes added to names..." 64 | 65 | yatmbn=$(basename "${yatmpath}") 66 | yatmhashexe="${yatmbn%.*}"_${yatmhash}."${yatmpath##*.}" 67 | echo " cp -n ${yatmpath} ${bindir}/${yatmhashexe}" 68 | cp -n ${yatmpath} ${bindir}/${yatmhashexe} 69 | chmod o+x ${bindir}/${yatmhashexe} || true 70 | chgrp ik11 ${bindir}/${yatmhashexe} || true 71 | 72 | fmsbn=$(basename "${fmspath}") 73 | fmshashexe="${fmsbn%.*}"_${fmshash}."${fmspath##*.}" 74 | echo " cp -n ${fmspath} ${bindir}/${fmshashexe}" 75 | cp -n ${fmspath} ${bindir}/${fmshashexe} 76 | chmod o+x ${bindir}/${fmshashexe} || true 77 | chgrp ik11 ${bindir}/${fmshashexe} || true 78 | 79 | cice1bn=$(basename "${cice1path}") 80 | cice1hashexe="${cice1bn%.*}"_${cicehash}."${cice1path##*.}" 81 | echo " cp -n ${cice1path} ${bindir}/${cice1hashexe}" 82 | cp -n ${cice1path} ${bindir}/${cice1hashexe} 83 | chmod o+x ${bindir}/${cice1hashexe} || true 84 | chgrp ik11 ${bindir}/${cice1hashexe} || true 85 | 86 | cice025bn=$(basename "${cice025path}") 87 | cice025hashexe="${cice025bn%.*}"_${cicehash}."${cice025path##*.}" 88 | echo " cp -n ${cice025path} ${bindir}/${cice025hashexe}" 89 | cp -n ${cice025path} ${bindir}/${cice025hashexe} 90 | chmod o+x ${bindir}/${cice025hashexe} || true 91 | chgrp ik11 ${bindir}/${cice025hashexe} || true 92 | 93 | cice010bn=$(basename "${cice010path}") 94 | cice010hashexe="${cice010bn%.*}"_${cicehash}."${cice010path##*.}" 95 | echo " cp -n ${cice010path} ${bindir}/${cice010hashexe}" 96 | cp -n ${cice010path} ${bindir}/${cice010hashexe} 97 | chmod o+x ${bindir}/${cice010hashexe} || true 98 | chgrp ik11 ${bindir}/${cice010hashexe} || true 99 | 100 | cice010bn_18x15=$(basename "${cice010path_18x15}") 101 | cice010hashexe_18x15="${cice010bn_18x15%.*}"_${cicehash}."${cice010path_18x15##*.}" 102 | echo " cp -n ${cice010path_18x15} ${bindir}/${cice010hashexe_18x15}" 103 | cp -n ${cice010path_18x15} ${bindir}/${cice010hashexe_18x15} 104 | chmod o+x ${bindir}/${cice010hashexe_18x15} || true 105 | chgrp ik11 ${bindir}/${cice010hashexe_18x15} || true 106 | 107 | echo " cp -n ${mppnccombinepath} ${bindir}/mppnccombine" 108 | cp -n ${mppnccombinepath} ${bindir}/mppnccombine # no hash for mppnccombine 109 | chmod o+x ${bindir}/mppnccombine || true # no hash for mppnccombine 110 | chgrp ik11 ${bindir}/mppnccombine || true # no hash for mppnccombine 111 | 112 | echo "Fixing exe in "${config1ryfpath}" to match executable names..." 113 | sed "s|exe:.*${yatmbn%.*}_.*|exe: ${bindir}/${yatmhashexe}|g" < ${config1ryfpath} > ${config1ryfpath}-tmp 114 | sed "s|exe:.*${fmsbn%.*}_.*|exe: ${bindir}/${fmshashexe}|g" < ${config1ryfpath}-tmp > ${config1ryfpath}-tmp2 115 | sed "s|exe:.*${cice1bn%.*}_.*|exe: ${bindir}/${cice1hashexe}|g" < ${config1ryfpath}-tmp2 > ${config1ryfpath}-tmp3 116 | diff ${config1ryfpath} ${config1ryfpath}-tmp3 || true 117 | mv ${config1ryfpath}-tmp3 ${config1ryfpath} 118 | rm ${config1ryfpath}-tmp* 119 | 120 | echo "Fixing exe in "${config025ryfpath}" to match executable names..." 121 | sed "s|exe:.*${yatmbn%.*}_.*|exe: ${bindir}/${yatmhashexe}|g" < ${config025ryfpath} > ${config025ryfpath}-tmp 122 | sed "s|exe:.*${fmsbn%.*}_.*|exe: ${bindir}/${fmshashexe}|g" < ${config025ryfpath}-tmp > ${config025ryfpath}-tmp2 123 | sed "s|exe:.*${cice025bn%.*}_.*|exe: ${bindir}/${cice025hashexe}|g" < ${config025ryfpath}-tmp2 > ${config025ryfpath}-tmp3 124 | diff ${config025ryfpath} ${config025ryfpath}-tmp3 || true 125 | mv ${config025ryfpath}-tmp3 ${config025ryfpath} 126 | rm ${config025ryfpath}-tmp* 127 | 128 | echo "Fixing exe in "${config010ryfpath}" to match executable names..." 129 | sed "s|exe:.*${yatmbn%.*}_.*|exe: ${bindir}/${yatmhashexe}|g" < ${config010ryfpath} > ${config010ryfpath}-tmp 130 | sed "s|exe:.*${fmsbn%.*}_.*|exe: ${bindir}/${fmshashexe}|g" < ${config010ryfpath}-tmp > ${config010ryfpath}-tmp2 131 | sed "s|exe:.*${cice010bn%.*}_.*|exe: ${bindir}/${cice010hashexe}|g" < ${config010ryfpath}-tmp2 > ${config010ryfpath}-tmp3 132 | diff ${config010ryfpath} ${config010ryfpath}-tmp3 || true 133 | mv ${config010ryfpath}-tmp3 ${config010ryfpath} 134 | rm ${config010ryfpath}-tmp* 135 | 136 | echo "Fixing exe in "${config1iafpath}" to match executable names..." 137 | sed "s|exe:.*${yatmbn%.*}_.*|exe: ${bindir}/${yatmhashexe}|g" < ${config1iafpath} > ${config1iafpath}-tmp 138 | sed "s|exe:.*${fmsbn%.*}_.*|exe: ${bindir}/${fmshashexe}|g" < ${config1iafpath}-tmp > ${config1iafpath}-tmp2 139 | sed "s|exe:.*${cice1bn%.*}_.*|exe: ${bindir}/${cice1hashexe}|g" < ${config1iafpath}-tmp2 > ${config1iafpath}-tmp3 140 | diff ${config1iafpath} ${config1iafpath}-tmp3 || true 141 | mv ${config1iafpath}-tmp3 ${config1iafpath} 142 | rm ${config1iafpath}-tmp* 143 | 144 | echo "Fixing exe in "${config025iafpath}" to match executable names..." 145 | sed "s|exe:.*${yatmbn%.*}_.*|exe: ${bindir}/${yatmhashexe}|g" < ${config025iafpath} > ${config025iafpath}-tmp 146 | sed "s|exe:.*${fmsbn%.*}_.*|exe: ${bindir}/${fmshashexe}|g" < ${config025iafpath}-tmp > ${config025iafpath}-tmp2 147 | sed "s|exe:.*${cice025bn%.*}_.*|exe: ${bindir}/${cice025hashexe}|g" < ${config025iafpath}-tmp2 > ${config025iafpath}-tmp3 148 | diff ${config025iafpath} ${config025iafpath}-tmp3 || true 149 | mv ${config025iafpath}-tmp3 ${config025iafpath} 150 | rm ${config025iafpath}-tmp* 151 | 152 | echo "Fixing exe in "${config010iafpath}" to match executable names..." 153 | sed "s|exe:.*${yatmbn%.*}_.*|exe: ${bindir}/${yatmhashexe}|g" < ${config010iafpath} > ${config010iafpath}-tmp 154 | sed "s|exe:.*${fmsbn%.*}_.*|exe: ${bindir}/${fmshashexe}|g" < ${config010iafpath}-tmp > ${config010iafpath}-tmp2 155 | sed "s|exe:.*${cice010bn%.*}_.*|exe: ${bindir}/${cice010hashexe}|g" < ${config010iafpath}-tmp2 > ${config010iafpath}-tmp3 156 | diff ${config010iafpath} ${config010iafpath}-tmp3 || true 157 | mv ${config010iafpath}-tmp3 ${config010iafpath} 158 | rm ${config010iafpath}-tmp* 159 | 160 | # TODO: fix sed script to handle changes of mom_type 161 | echo 162 | echo "WARNING: if your previous exe mom_type was not ${mom_type} it will need to be manually updated in the config.yaml file" 163 | echo 164 | sleep 1 165 | 166 | echo "$(basename $BASH_SOURCE) completed." 167 | 168 | -------------------------------------------------------------------------------- /hashexe.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Copy ACCESS-OM2 executables to bin with githash in name, and config.yaml to match. 4 | # All changes to config.yaml are reported. 5 | # Andrew Kiss https://github.com/aekiss 6 | 7 | set -e 8 | 9 | if [[ -z "${ACCESS_OM_DIR}" ]]; then 10 | export ACCESS_OM_DIR=$(pwd) 11 | fi 12 | 13 | if [[ -z "${mom_type}" ]]; then 14 | echo "FATAL ERROR: mom_type not set. Need to do whichever of these is appropriate" 15 | echo " export mom_type=ACCESS-OM" 16 | echo "or" 17 | echo " export mom_type=ACCESS-OM-BGC" 18 | echo "taking into account the branches the control dirs are on:" 19 | for d in control/*; do cd $d; echo $d; git status | grep "On branch"; cd -; done 20 | exit 1 21 | fi 22 | 23 | yatmpath=${ACCESS_OM_DIR}/src/libaccessom2/build/bin/yatm.exe 24 | fmspath=${ACCESS_OM_DIR}/src/mom/exec/nci/${mom_type}/fms_${mom_type}.x 25 | cice1path=${ACCESS_OM_DIR}/src/cice5/build_auscom_360x300_24p/cice_auscom_360x300_24p.exe 26 | cice025path=${ACCESS_OM_DIR}/src/cice5/build_auscom_1440x1080_480p/cice_auscom_1440x1080_480p.exe 27 | cice010path=${ACCESS_OM_DIR}/src/cice5/build_auscom_3600x2700_722p/cice_auscom_3600x2700_722p.exe 28 | cice010path_18x15=${ACCESS_OM_DIR}/src/cice5/build_auscom_18x15.3600x2700_1682p/cice_auscom_18x15.3600x2700_1682p.exe 29 | mppnccombinepath=${ACCESS_OM_DIR}/src/mom/bin/mppnccombine.nci 30 | 31 | config1ryfpath=${ACCESS_OM_DIR}/control/1deg_jra55_ryf/config.yaml 32 | config025ryfpath=${ACCESS_OM_DIR}/control/025deg_jra55_ryf/config.yaml 33 | config010ryfpath=${ACCESS_OM_DIR}/control/01deg_jra55_ryf/config.yaml 34 | 35 | config1iafpath=${ACCESS_OM_DIR}/control/1deg_jra55_iaf/config.yaml 36 | config025iafpath=${ACCESS_OM_DIR}/control/025deg_jra55_iaf/config.yaml 37 | config010iafpath=${ACCESS_OM_DIR}/control/01deg_jra55_iaf/config.yaml 38 | 39 | bindir=${ACCESS_OM_DIR}/bin 40 | 41 | mkdir -p ${bindir} 42 | 43 | echo "Getting executable hashes..." 44 | 45 | cd $(dirname "${yatmpath}") && yatmhash=`git rev-parse --short=7 HEAD` 46 | test -z "$(git status --porcelain)" || yatmhash=${yatmhash}-modified # uncommitted changes or untracked files 47 | cd $(dirname "${fmspath}") && fmshash=`git rev-parse --short=7 HEAD` 48 | test -z "$(git status --porcelain)" || fmshash=${fmshash}-modified # uncommitted changes or untracked files 49 | fmshash=${fmshash}_libaccessom2_${yatmhash} # also track libaccessom2 50 | cd $(dirname "${cice1path}") && cicehash=`git rev-parse --short=7 HEAD` # NB only one hash for all three cice builds 51 | test -z "$(git status --porcelain)" || cicehash=${cicehash}-modified # uncommitted changes or untracked files 52 | cicehash=${cicehash}_libaccessom2_${yatmhash} # also track libaccessom2 53 | 54 | echo "Copying executables to "${bindir}" with hashes added to names..." 55 | 56 | yatmbn=$(basename "${yatmpath}") 57 | yatmhashexe="${yatmbn%.*}"_${yatmhash}."${yatmpath##*.}" 58 | echo " cp ${yatmpath} ${bindir}/${yatmhashexe}" 59 | cp ${yatmpath} ${bindir}/${yatmhashexe} 60 | 61 | fmsbn=$(basename "${fmspath}") 62 | fmshashexe="${fmsbn%.*}"_${fmshash}."${fmspath##*.}" 63 | echo " cp ${fmspath} ${bindir}/${fmshashexe}" 64 | cp ${fmspath} ${bindir}/${fmshashexe} 65 | 66 | cice1bn=$(basename "${cice1path}") 67 | cice1hashexe="${cice1bn%.*}"_${cicehash}."${cice1path##*.}" 68 | echo " cp ${cice1path} ${bindir}/${cice1hashexe}" 69 | cp ${cice1path} ${bindir}/${cice1hashexe} 70 | 71 | cice025bn=$(basename "${cice025path}") 72 | cice025hashexe="${cice025bn%.*}"_${cicehash}."${cice025path##*.}" 73 | echo " cp ${cice025path} ${bindir}/${cice025hashexe}" 74 | cp ${cice025path} ${bindir}/${cice025hashexe} 75 | 76 | cice010bn=$(basename "${cice010path}") 77 | cice010hashexe="${cice010bn%.*}"_${cicehash}."${cice010path##*.}" 78 | echo " cp ${cice010path} ${bindir}/${cice010hashexe}" 79 | cp ${cice010path} ${bindir}/${cice010hashexe} 80 | 81 | cice010bn_18x15=$(basename "${cice010path_18x15}") 82 | cice010hashexe_18x15="${cice010bn_18x15%.*}"_${cicehash}."${cice010path_18x15##*.}" 83 | echo " cp ${cice010path_18x15} ${bindir}/${cice010hashexe_18x15}" 84 | cp ${cice010path_18x15} ${bindir}/${cice010hashexe_18x15} 85 | 86 | echo " cp ${mppnccombinepath} ${bindir}/mppnccombine" 87 | cp ${mppnccombinepath} ${bindir}/mppnccombine # no hash for mppnccombine 88 | 89 | echo "Fixing exe in "${config1ryfpath}" to match executable names..." 90 | sed "s|exe:.*${yatmbn%.*}_.*|exe: ${bindir}/${yatmhashexe}|g" < ${config1ryfpath} > ${config1ryfpath}-tmp 91 | sed "s|exe:.*${fmsbn%.*}_.*|exe: ${bindir}/${fmshashexe}|g" < ${config1ryfpath}-tmp > ${config1ryfpath}-tmp2 92 | sed "s|exe:.*${cice1bn%.*}_.*|exe: ${bindir}/${cice1hashexe}|g" < ${config1ryfpath}-tmp2 > ${config1ryfpath}-tmp3 93 | diff ${config1ryfpath} ${config1ryfpath}-tmp3 || true 94 | mv ${config1ryfpath}-tmp3 ${config1ryfpath} 95 | rm ${config1ryfpath}-tmp* 96 | 97 | echo "Fixing exe in "${config025ryfpath}" to match executable names..." 98 | sed "s|exe:.*${yatmbn%.*}_.*|exe: ${bindir}/${yatmhashexe}|g" < ${config025ryfpath} > ${config025ryfpath}-tmp 99 | sed "s|exe:.*${fmsbn%.*}_.*|exe: ${bindir}/${fmshashexe}|g" < ${config025ryfpath}-tmp > ${config025ryfpath}-tmp2 100 | sed "s|exe:.*${cice025bn%.*}_.*|exe: ${bindir}/${cice025hashexe}|g" < ${config025ryfpath}-tmp2 > ${config025ryfpath}-tmp3 101 | diff ${config025ryfpath} ${config025ryfpath}-tmp3 || true 102 | mv ${config025ryfpath}-tmp3 ${config025ryfpath} 103 | rm ${config025ryfpath}-tmp* 104 | 105 | echo "Fixing exe in "${config010ryfpath}" to match executable names..." 106 | sed "s|exe:.*${yatmbn%.*}_.*|exe: ${bindir}/${yatmhashexe}|g" < ${config010ryfpath} > ${config010ryfpath}-tmp 107 | sed "s|exe:.*${fmsbn%.*}_.*|exe: ${bindir}/${fmshashexe}|g" < ${config010ryfpath}-tmp > ${config010ryfpath}-tmp2 108 | sed "s|exe:.*${cice010bn%.*}_.*|exe: ${bindir}/${cice010hashexe}|g" < ${config010ryfpath}-tmp2 > ${config010ryfpath}-tmp3 109 | diff ${config010ryfpath} ${config010ryfpath}-tmp3 || true 110 | mv ${config010ryfpath}-tmp3 ${config010ryfpath} 111 | rm ${config010ryfpath}-tmp* 112 | 113 | echo "Fixing exe in "${config1iafpath}" to match executable names..." 114 | sed "s|exe:.*${yatmbn%.*}_.*|exe: ${bindir}/${yatmhashexe}|g" < ${config1iafpath} > ${config1iafpath}-tmp 115 | sed "s|exe:.*${fmsbn%.*}_.*|exe: ${bindir}/${fmshashexe}|g" < ${config1iafpath}-tmp > ${config1iafpath}-tmp2 116 | sed "s|exe:.*${cice1bn%.*}_.*|exe: ${bindir}/${cice1hashexe}|g" < ${config1iafpath}-tmp2 > ${config1iafpath}-tmp3 117 | diff ${config1iafpath} ${config1iafpath}-tmp3 || true 118 | mv ${config1iafpath}-tmp3 ${config1iafpath} 119 | rm ${config1iafpath}-tmp* 120 | 121 | echo "Fixing exe in "${config025iafpath}" to match executable names..." 122 | sed "s|exe:.*${yatmbn%.*}_.*|exe: ${bindir}/${yatmhashexe}|g" < ${config025iafpath} > ${config025iafpath}-tmp 123 | sed "s|exe:.*${fmsbn%.*}_.*|exe: ${bindir}/${fmshashexe}|g" < ${config025iafpath}-tmp > ${config025iafpath}-tmp2 124 | sed "s|exe:.*${cice025bn%.*}_.*|exe: ${bindir}/${cice025hashexe}|g" < ${config025iafpath}-tmp2 > ${config025iafpath}-tmp3 125 | diff ${config025iafpath} ${config025iafpath}-tmp3 || true 126 | mv ${config025iafpath}-tmp3 ${config025iafpath} 127 | rm ${config025iafpath}-tmp* 128 | 129 | echo "Fixing exe in "${config010iafpath}" to match executable names..." 130 | sed "s|exe:.*${yatmbn%.*}_.*|exe: ${bindir}/${yatmhashexe}|g" < ${config010iafpath} > ${config010iafpath}-tmp 131 | sed "s|exe:.*${fmsbn%.*}_.*|exe: ${bindir}/${fmshashexe}|g" < ${config010iafpath}-tmp > ${config010iafpath}-tmp2 132 | sed "s|exe:.*${cice010bn%.*}_.*|exe: ${bindir}/${cice010hashexe}|g" < ${config010iafpath}-tmp2 > ${config010iafpath}-tmp3 133 | diff ${config010iafpath} ${config010iafpath}-tmp3 || true 134 | mv ${config010iafpath}-tmp3 ${config010iafpath} 135 | rm ${config010iafpath}-tmp* 136 | 137 | # TODO: fix sed script to handle changes of mom_type 138 | echo 139 | echo "WARNING: if your previous exe mom_type was not ${mom_type} it will need to be manually updated in the config.yaml file" 140 | echo 141 | sleep 1 142 | 143 | echo "$(basename $BASH_SOURCE) completed." 144 | 145 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Compile ACCESS-OM2 at 1, 1/4 and 1/10 degree resolution with JRA-55-do forcing 4 | # Andrew Kiss https://github.com/aekiss 5 | 6 | set -e 7 | 8 | #Type of MOM installation 9 | 10 | export mom_type=ACCESS-OM 11 | #export mom_type=ACCESS-OM-BGC 12 | 13 | echo "MOM5 build is of type mom_type=${mom_type}" 14 | sleep 1 15 | 16 | # Disable user gitconfig 17 | export GIT_CONFIG_NOGLOBAL=yes 18 | 19 | if [[ -z "${ACCESS_OM_DIR}" ]]; then 20 | echo "Installing ACCESS-OM2 in $(pwd)" 21 | export ACCESS_OM_DIR=$(pwd) 22 | fi 23 | export LIBACCESSOM2_ROOT=$ACCESS_OM_DIR/src/libaccessom2 24 | 25 | declare -a exepaths=(${ACCESS_OM_DIR}/src/mom/exec/nci/${mom_type}/fms_${mom_type}.x ${LIBACCESSOM2_ROOT}/build/bin/yatm.exe ${ACCESS_OM_DIR}/src/cice5/build_auscom_360x300_24p/cice_auscom_360x300_24p.exe ${ACCESS_OM_DIR}/src/cice5/build_auscom_1440x1080_480p/cice_auscom_1440x1080_480p.exe ${ACCESS_OM_DIR}/src/cice5/build_auscom_3600x2700_722p/cice_auscom_3600x2700_722p.exe ${ACCESS_OM_DIR}/src/cice5/build_auscom_18x15.3600x2700_1682p/cice_auscom_18x15.3600x2700_1682p.exe ${ACCESS_OM_DIR}/src/mom/bin/mppnccombine.nci) 26 | # ${ACCESS_OM_DIR}/src/matm/build_nt62/matm_nt62.exe 27 | # ${ACCESS_OM_DIR}/src/matm/build_jra55/matm_jra55.exe 28 | 29 | cd ${ACCESS_OM_DIR} 30 | 31 | # echo "Downloading experiment input data and creating directories..." 32 | # ${ACCESS_OM_DIR}/get_input_data.py 33 | 34 | echo 35 | echo "Removing previous executables (if any)..." 36 | for p in "${exepaths[@]}" 37 | do 38 | rm ${p} && echo "rm ${p}" 39 | done 40 | 41 | echo 42 | echo "Compiling YATM file-based atmosphere and libaccessom2... " 43 | cd ${LIBACCESSOM2_ROOT} 44 | source ./build_on_gadi.sh 45 | 46 | echo 47 | echo "Compiling MOM5.1..." 48 | cd ${ACCESS_OM_DIR}/src/mom/exp 49 | ./MOM_compile.csh --type $mom_type --platform nci 50 | 51 | cd ${ACCESS_OM_DIR}/src/cice5 52 | echo 53 | echo "Compiling CICE5.1 at 1 degree..." 54 | make # 1 degree 55 | echo 56 | echo "Compiling CICE5.1 at 1/4 degree..." 57 | make 025deg 58 | echo 59 | echo "Compiling CICE5.1 at 1/10 degree..." 60 | make 01deg 61 | echo 62 | echo "Compiling CICE5.1 at 1/10 degree with more blocks..." 63 | make 01deg_18x15 64 | 65 | echo 66 | echo "Checking all executables have been built..." 67 | for p in "${exepaths[@]}" 68 | do 69 | ls ${p} || { echo "Build failed!"; exit 1; } 70 | done 71 | 72 | echo 73 | source ${ACCESS_OM_DIR}/hashexe.sh 74 | 75 | cd ${ACCESS_OM_DIR} 76 | echo 77 | echo "Executables were built using these library versions:" 78 | source ${ACCESS_OM_DIR}/libcheck.sh 79 | 80 | echo 81 | echo "$(basename "$0") completed." 82 | echo 83 | 84 | # exit 0 85 | 86 | -------------------------------------------------------------------------------- /libcheck.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Report library versions used in model components of ACCESS-OM2 4 | # Andrew Kiss https://github.com/aekiss 5 | # mom_type= ACCESS-OM for default or ACCESS-OM-BGC for WOMBAT :RASF 6 | 7 | if [[ -z "${ACCESS_OM_DIR}" ]]; then 8 | export ACCESS_OM_DIR=$(pwd) 9 | fi 10 | if [[ -z "${LIBACCESSOM2_ROOT}" ]]; then 11 | export LIBACCESSOM2_ROOT=$ACCESS_OM_DIR/src/libaccessom2 12 | fi 13 | if [[ -z "${mom_type}" ]]; then 14 | export mom_type=ACCESS-OM-BGC 15 | fi 16 | 17 | declare -a libs=(openmpi netcdf) 18 | 19 | declare -a paths=(${ACCESS_OM_DIR}/src/mom/bin/environs.nci ${ACCESS_OM_DIR}/src/cice5/bld/config.nci.auscom.360x300 ${ACCESS_OM_DIR}/src/cice5/bld/config.nci.auscom.1440x1080 ${ACCESS_OM_DIR}/src/cice5/bld/config.nci.auscom.3600x2700 ${ACCESS_OM_DIR}/src/cice5/bld/config.nci.auscom.18x15.3600x2700 ${LIBACCESSOM2_ROOT}/build_on_gadi.sh ${LIBACCESSOM2_ROOT}/oasis3-mct/util/make_dir/config.gadi) 20 | 21 | declare -a exepaths=(${ACCESS_OM_DIR}/src/mom/exec/nci/${mom_type}/fms_${mom_type}.x ${ACCESS_OM_DIR}/src/cice5/build_auscom_360x300_24p/cice_auscom_360x300_24p.exe ${ACCESS_OM_DIR}/src/cice5/build_auscom_1440x1080_480p/cice_auscom_1440x1080_480p.exe ${ACCESS_OM_DIR}/src/cice5/build_auscom_3600x2700_722p/cice_auscom_3600x2700_722p.exe ${ACCESS_OM_DIR}/src/cice5/build_auscom_18x15.3600x2700_1682p/cice_auscom_18x15.3600x2700_1682p.exe ${LIBACCESSOM2_ROOT}/build/bin/yatm.exe ${ACCESS_OM_DIR}/src/mom/bin/mppnccombine.nci) 22 | 23 | for l in "${libs[@]}" 24 | do 25 | echo $l library versions used: 26 | echo " in build scripts:" 27 | for p in "${paths[@]}" 28 | do 29 | echo -n " " 30 | grep -H $l $p 31 | done 32 | echo " in executables:" 33 | for p in "${exepaths[@]}" 34 | do 35 | echo " $p: " 36 | ldd $p | grep $l || true 37 | done 38 | done 39 | 40 | -------------------------------------------------------------------------------- /test/checksums/cm_1440x1080-test.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSIMA/access-om2/c35ebfaaaf287041b42998f1a9a40191cef9b79b/test/checksums/cm_1440x1080-test.txt -------------------------------------------------------------------------------- /test/checksums/cm_360x300-test.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSIMA/access-om2/c35ebfaaaf287041b42998f1a9a40191cef9b79b/test/checksums/cm_360x300-test.txt -------------------------------------------------------------------------------- /test/checksums/om_1440x1080-test.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSIMA/access-om2/c35ebfaaaf287041b42998f1a9a40191cef9b79b/test/checksums/om_1440x1080-test.txt -------------------------------------------------------------------------------- /test/dump_field.F90: -------------------------------------------------------------------------------- 1 | 2 | module dump_field 3 | 4 | ! Dump a field. Subsequent calls with the same field name and proc will a new 5 | ! time point to the same file. See the test program below for use. 6 | 7 | use netcdf 8 | implicit none 9 | 10 | private 11 | public dump_field_2d, dump_field_close 12 | 13 | type field_info_type 14 | integer :: count 15 | integer :: ncid 16 | integer :: varid 17 | integer :: min_varid 18 | integer :: max_varid 19 | integer :: mean_varid 20 | character(len=256) :: field_name 21 | end type field_info_type 22 | 23 | ! Array containing list of field names and associated data, e.g. ncid. 24 | integer, parameter :: MAX_FIELDS = 256 25 | type (field_info_type), dimension(MAX_FIELDS) :: field_info 26 | integer :: field_num = 1 27 | 28 | contains 29 | 30 | subroutine setup_2d(field_name, proc_num, nx, ny, do_full_dump) 31 | 32 | character(len=*), intent(in) :: field_name 33 | integer, intent(in) :: nx, ny, proc_num 34 | logical, intent(in) :: do_full_dump 35 | 36 | integer :: ncid, varid, min_varid, max_varid, mean_varid, x_dimid, y_dimid, t_dimid 37 | character(len=6) :: proc_str 38 | 39 | if (proc_num > 999999) then 40 | stop 'Error: dump_field::setup_2d(), proc_num too high.' 41 | endif 42 | 43 | write(proc_str, '(I6.6)') proc_num 44 | 45 | ! Open a file, set up a meta-data needed to save the field. 46 | call check(nf90_create(field_name//'.'//proc_str//'.nc', NF90_CLOBBER, ncid)) 47 | call check(nf90_def_dim(ncid, 't', NF90_UNLIMITED, t_dimid)) 48 | if (do_full_dump) then 49 | call check(nf90_def_dim(ncid, 'x', nx, x_dimid)) 50 | call check(nf90_def_dim(ncid, 'y', ny, y_dimid)) 51 | call check(nf90_def_var(ncid, field_name, NF90_REAL, (/ x_dimid, y_dimid, t_dimid /), varid)) 52 | field_info(field_num)%varid = varid 53 | endif 54 | call check(nf90_def_var(ncid, field_name//'_min', NF90_REAL, (/ t_dimid /), min_varid)) 55 | call check(nf90_def_var(ncid, field_name//'_max', NF90_REAL, (/ t_dimid /), max_varid)) 56 | call check(nf90_def_var(ncid, field_name//'_mean', NF90_REAL, (/ t_dimid /), mean_varid)) 57 | call check(nf90_enddef(ncid)) 58 | 59 | field_info(field_num)%field_name = field_name 60 | field_info(field_num)%ncid = ncid 61 | field_info(field_num)%min_varid = min_varid 62 | field_info(field_num)%max_varid = max_varid 63 | field_info(field_num)%mean_varid = mean_varid 64 | field_info(field_num)%count = 1 65 | 66 | field_num = field_num + 1 67 | if (field_num > MAX_FIELDS) then 68 | stop 'Error: dump_field::setup_2d(), too many fields.' 69 | endif 70 | 71 | end subroutine 72 | 73 | subroutine dump_field_2d(field_name, proc_num, field_data, do_full_dump) 74 | ! Search through field names and find appropriate file handle. 75 | ! Save to file. 76 | 77 | character(len=*), intent(in) :: field_name 78 | integer, intent(in) :: proc_num 79 | real, dimension(:,:), intent(in) :: field_data 80 | logical, intent(in), optional :: do_full_dump 81 | 82 | real :: mean 83 | integer :: start(3), data_size(3), idx 84 | logical :: found, dump 85 | 86 | found = .false. 87 | dump = .false. 88 | 89 | if (present(do_full_dump)) then 90 | dump = do_full_dump 91 | end if 92 | 93 | call get_index(field_name, idx, found) 94 | if (.not. found) then 95 | call setup_2d(field_name, proc_num, size(field_data, 1), size(field_data, 2), dump) 96 | end if 97 | 98 | call get_index(field_name, idx, found) 99 | if (.not. found) then 100 | stop 'save_field_mod::field_write' 101 | end if 102 | 103 | data_size = (/ size(field_data, 1), size(field_data, 2), 1 /) 104 | start = (/ 1, 1, field_info(idx)%count /) 105 | 106 | ! Dump data 107 | if (dump) then 108 | call check(nf90_put_var(field_info(idx)%ncid, field_info(idx)%varid, field_data, start=start, count=data_size)) 109 | end if 110 | 111 | ! Write out some stats. 112 | call check(nf90_put_var(field_info(idx)%ncid, field_info(idx)%max_varid, (/ maxval(field_data) /), & 113 | start=(/ field_info(idx)%count /), count=(/ 1 /))) 114 | call check(nf90_put_var(field_info(idx)%ncid, field_info(idx)%min_varid, (/ minval(field_data) /), & 115 | start=(/ field_info(idx)%count /), count=(/ 1 /))) 116 | mean = sum(field_data) / (size(field_data, 1) * size(field_data, 2)) 117 | call check(nf90_put_var(field_info(idx)%ncid, field_info(idx)%mean_varid, (/ mean /), & 118 | start=(/ field_info(idx)%count /), count=(/ 1 /))) 119 | 120 | call check(nf90_sync(field_info(idx)%ncid)) 121 | 122 | field_info(idx)%count = field_info(idx)%count + 1 123 | 124 | end subroutine 125 | 126 | subroutine dump_field_close(field_name) 127 | 128 | character(len=*), intent(in) :: field_name 129 | 130 | integer :: idx 131 | logical :: found 132 | 133 | call get_index(field_name, idx, found) 134 | if (.not. found) then 135 | stop 'save_field_mod::field_close()' 136 | end if 137 | 138 | call check(nf90_close(field_info(idx)%ncid)) 139 | 140 | end subroutine 141 | 142 | subroutine get_index(field_name, idx, found) 143 | 144 | character(len=*), intent(in) :: field_name 145 | integer, intent(out) :: idx 146 | logical, intent(out) :: found 147 | 148 | found = .false. 149 | do idx=1, field_num 150 | if (field_name == field_info(idx)%field_name) then 151 | found = .true. 152 | return 153 | end if 154 | end do 155 | 156 | end subroutine get_index 157 | 158 | subroutine check(status) 159 | integer, intent ( in) :: status 160 | 161 | if(status /= nf90_noerr) then 162 | print *, trim(nf90_strerror(status)) 163 | stop 'save_field_mod::check()' 164 | end if 165 | end subroutine check 166 | 167 | end module 168 | 169 | program test_dump_field 170 | 171 | use dump_field 172 | 173 | real, dimension(3, 3) :: array 174 | 175 | array = reshape((/ 12.0, 32.0, 1.23123, 55.0, 3322.0, 65.0, 0.123, 99.0, 10.0 /), shape(array)) 176 | call dump_field_2d('sst', 4, array, .true.) 177 | 178 | array = reshape((/ 3099.0, 554343.0, 0.3221, 405.0, 23.0, 56.0, 123.0, 89.0, 0.000002 /), shape(array)) 179 | call dump_field_2d('sst', 4, array, .true.) 180 | 181 | call dump_field_close('sst') 182 | 183 | end program 184 | 185 | -------------------------------------------------------------------------------- /test/exp_test_helper.py: -------------------------------------------------------------------------------- 1 | 2 | from __future__ import print_function 3 | 4 | import subprocess as sp 5 | import sys 6 | import stat 7 | import shutil 8 | import re 9 | import os 10 | import sys 11 | import glob 12 | import time 13 | import yaml 14 | 15 | from util import wait_for_qsub, get_git_hash 16 | 17 | class ExpTestHelper(object): 18 | 19 | def __init__(self, exp_name, bin_path=None): 20 | 21 | self.exp_name = exp_name 22 | self.res = exp_name.split('deg')[0].split('_')[-1] + 'deg' 23 | 24 | self.my_path = os.path.dirname(os.path.realpath(__file__)) 25 | self.lab_path = os.path.realpath(os.path.join(self.my_path, '../')) 26 | if not bin_path: 27 | self.bin_path = os.path.join(self.lab_path, 'bin') 28 | else: 29 | self.bin_path = bin_path 30 | self.control_path = os.path.join(self.lab_path, 'control') 31 | self.exp_path = os.path.join(self.control_path, exp_name) 32 | self.payu_config = os.path.join(self.exp_path, 'config.yaml') 33 | self.accessom2_config = os.path.join(self.exp_path, 'accessom2.nml') 34 | self.ocean_config = os.path.join(self.exp_path, 'ocean', 'input.nml') 35 | self.archive = os.path.join(self.lab_path, 'archive', exp_name) 36 | self.output000 = os.path.join(self.archive, 'output000') 37 | self.output001 = os.path.join(self.archive, 'output001') 38 | self.accessom2_out_000 = os.path.join(self.output000, 'access-om2.out') 39 | self.accessom2_out_001 = os.path.join(self.output001, 'access-om2.out') 40 | 41 | self.src = os.path.join(self.lab_path, 'src') 42 | 43 | self.libaccessom2_src = os.path.join(self.src, 'libaccessom2') 44 | self.mom_src = os.path.join(self.src, 'mom') 45 | self.cice_src = os.path.join(self.src, 'cice5') 46 | self.yatm_exe = None 47 | self.mom_exe = None 48 | self.cice_exe = None 49 | self.input_path = '/short/public/access-om2/input_rc' 50 | 51 | self.mom_input = os.path.join(self.input_path, 'mom_' + self.res) 52 | self.cice_input = os.path.join(self.input_path, 'cice_' + self.res) 53 | 54 | if not os.path.exists(self.bin_path): 55 | os.mkdir(self.bin_path) 56 | 57 | def has_run(self): 58 | """ 59 | See wether this experiment has been run. 60 | """ 61 | 62 | return os.path.exists(os.path.join(self.output000, 'access-om2.out')) 63 | 64 | def make_paths(self, exp_name, run_num=0): 65 | paths = {} 66 | run_num = str(run_num).zfill(3) 67 | 68 | paths['archive_link'] = os.path.join(paths['exp'], 'archive') 69 | paths['output'] = os.path.join(paths['archive'], 'output' + run_num) 70 | paths['restart'] = os.path.join(paths['archive'], 'restart' + run_num) 71 | paths['stdout'] = os.path.join(paths['output'], 'access.out') 72 | paths['stderr'] = os.path.join(paths['output'], 'access.err') 73 | 74 | paths['stdout_runtime'] = os.path.join(paths['exp'], 'access.out') 75 | paths['stderr_runtime'] = os.path.join(paths['exp'], 'access.err') 76 | 77 | return paths 78 | 79 | def print_output(self, files): 80 | 81 | for file in files: 82 | if file is not None: 83 | if os.path.exists(file): 84 | with open(file, 'r') as f: 85 | print(f.read()) 86 | 87 | def get_most_recent_run_num(self, archive_path): 88 | """ 89 | Look in the archive directory to find which build this is. 90 | """ 91 | 92 | dirs = glob.glob(archive_path + '/output*') 93 | dirs.sort() 94 | 95 | return int(dirs[-1][-3:]) 96 | 97 | def setup_for_programmatic_run(self, exes): 98 | """ 99 | Various config.yaml settings need to be modified in order to run in the 100 | test environment. 101 | """ 102 | 103 | yatm_exe, cice_exe, mom_exe = exes 104 | 105 | with open(self.payu_config) as f: 106 | doc = yaml.safe_load(f) 107 | 108 | doc['submodels'][0]['exe'] = yatm_exe 109 | doc['submodels'][1]['exe'] = mom_exe 110 | doc['submodels'][2]['exe'] = cice_exe 111 | doc['runlog'] = False 112 | 113 | with open(self.payu_config, 'w') as f: 114 | yaml.dump(doc, f) 115 | 116 | def do_basic_access_run(self, exp, model='cm'): 117 | paths = self.make_paths(exp) 118 | ret, qso, qse, qsub_files = self.run() 119 | if ret != 0: 120 | self.print_output([qso, qse, 121 | paths['stdout_runtime'], 122 | paths['stderr_runtime']]) 123 | fstring = 'Run {} failed with code {}.' 124 | print(fstring.format(exp, ret), file=sys.stderr) 125 | assert(ret == 0) 126 | 127 | run_num = self.get_most_recent_run_num(paths['archive']) 128 | paths = self.make_paths(exp, run_num) 129 | 130 | # Model output should exist. 131 | assert(os.path.exists(paths['output'])) 132 | assert(os.path.exists(paths['restart'])) 133 | assert(os.path.exists(paths['stdout'])) 134 | assert(os.path.exists(paths['stderr'])) 135 | 136 | with open(paths['stdout'], 'r') as f: 137 | s = f.read() 138 | assert('MOM4: --- completed ---' in s) 139 | if model == 'om': 140 | assert('********** End of MATM **********' in s) 141 | 142 | def copy_to_bin(self, src_dir, wildcard, libaccessom2_src=None): 143 | exes = glob.glob(wildcard) 144 | if len(exes) != 1: 145 | print("Error: copy_to_bin can't find one {}".format(wildcard), file=sys.stderr) 146 | return None, 1 147 | exe = exes[0] 148 | 149 | ghash = get_git_hash(src_dir) 150 | if libaccessom2_src: 151 | libaccessom2_hash = get_git_hash(libaccessom2_src) 152 | else: 153 | libaccessom2_hash = None 154 | 155 | eb = os.path.basename(exe) 156 | if libaccessom2_hash: 157 | new_name = '{}_{}_libaccessom2_{}.{}'.format(eb.split('.')[0], ghash, 158 | libaccessom2_hash, eb.split('.')[1]) 159 | else: 160 | new_name = '{}_{}.{}'.format(eb.split('.')[0], ghash, 161 | eb.split('.')[1]) 162 | dest = os.path.join(self.bin_path, new_name) 163 | if os.path.exists(dest): 164 | os.remove(dest) 165 | 166 | shutil.copy(exe, dest) 167 | shutil.chown(dest, group='ik11') 168 | perms = stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH | stat.S_IXUSR \ 169 | | stat.S_IXGRP | stat.S_IXOTH 170 | os.chmod(dest, perms) 171 | 172 | return dest, 0 173 | 174 | 175 | def build_libaccessom2(self, clean=False): 176 | """ 177 | Note: the 'clean' arg does nothing. 178 | """ 179 | 180 | r1 = sp.call([os.path.join(self.libaccessom2_src, 'build_on_gadi.sh')]) 181 | exename, r2 = self.copy_to_bin(self.libaccessom2_src, 182 | self.libaccessom2_src + '/build/bin/yatm.exe') 183 | return exename, r1 + r2 184 | 185 | def build_cice(self, clean=False): 186 | os.environ['ACCESS_OM_DIR'] = os.path.join(self.lab_path) 187 | os.environ['LIBACCESSOM2_ROOT'] = os.path.join(self.libaccessom2_src) 188 | if clean: 189 | r1 = sp.call(['make', '-C', self.cice_src, 'clean']) 190 | r1 = sp.call(['make', '-C', self.cice_src, self.res]) 191 | 192 | if self.res == '025deg': 193 | exe_res = '1440x1080' 194 | elif self.res == '01deg': 195 | exe_res = '3600x2700' 196 | elif self.res == '1deg': 197 | exe_res = '360x300' 198 | else: 199 | assert False 200 | 201 | build_dir_wildcard = self.cice_src + '/build_*_' + exe_res + '_*p/*.exe' 202 | exename, r2 = self.copy_to_bin(self.cice_src, build_dir_wildcard, 203 | self.libaccessom2_src) 204 | 205 | return exename, r1 + r2 206 | 207 | def build_mom(self, clean=False): 208 | """ 209 | Note: the 'clean' arg does nothing. 210 | """ 211 | 212 | os.environ['ACCESS_OM_DIR'] = os.path.join(self.lab_path) 213 | os.environ['LIBACCESSOM2_ROOT'] = os.path.join(self.libaccessom2_src) 214 | 215 | mydir = os.getcwd() 216 | os.chdir(os.path.join(self.mom_src, 'exp')) 217 | r1 = sp.call(['./MOM_compile.csh', '--type', 'ACCESS-OM', 218 | '--platform', 'nci', '--repro']) 219 | os.chdir(mydir) 220 | 221 | exename, r2 = self.copy_to_bin(self.mom_src, 222 | self.mom_src + '/exec/nci/ACCESS-OM/*.x', 223 | self.libaccessom2_src) 224 | return exename, r1 + r2 225 | 226 | def build(self, clean=False): 227 | 228 | self.yatm_exe, r1 = self.build_libaccessom2(clean) 229 | if r1 != 0: 230 | print('YATM build failed for exp {}'.format(self.exp_name), 231 | file=sys.stderr) 232 | return r1 233 | self.cice_exe, r2 = self.build_cice(clean) 234 | if r2 != 0: 235 | print('CICE build failed for exp {}'.format(self.exp_name), 236 | file=sys.stderr) 237 | 238 | self.mom_exe, r3 = self.build_mom(clean) 239 | if r3 != 0: 240 | print('MOM build failed for exp {}'.format(self.exp_name), 241 | file=sys.stderr) 242 | 243 | return [self.yatm_exe, self.cice_exe, self.mom_exe], r1 + r2 + r3 244 | 245 | def run(self): 246 | """ 247 | Run the experiment using payu and check output. 248 | 249 | Don't do any work if it has already run. 250 | """ 251 | 252 | if self.has_run(): 253 | return 0, None, None, None 254 | else: 255 | return self.force_run() 256 | 257 | def force_qsub_run(self): 258 | """ 259 | Run using qsub 260 | """ 261 | 262 | # Change to experiment directory and run. 263 | try: 264 | os.chdir(self.exp_path) 265 | sp.check_output(['payu', 'sweep', '--lab', self.lab_path]) 266 | run_id = sp.check_output(['payu', 'run', '--lab', self.lab_path]) 267 | run_id = run_id.decode().splitlines()[0] 268 | os.chdir(self.my_path) 269 | except sp.CalledProcessError as err: 270 | os.chdir(self.my_path) 271 | print('Error: call to payu run failed.', file=sys.stderr) 272 | return 1, None, None, None 273 | 274 | wait_for_qsub(run_id) 275 | run_id = run_id.split('.')[0] 276 | 277 | output_files = [] 278 | # Read qsub stdout file 279 | stdout_filename = glob.glob(os.path.join(self.exp_path, 280 | '*.o{}'.format(run_id))) 281 | if len(stdout_filename) != 1: 282 | print('Error: there are too many stdout files.', file=sys.stderr) 283 | return 2, None, None, None 284 | 285 | stdout_filename = stdout_filename[0] 286 | output_files.append(stdout_filename) 287 | stdout = '' 288 | with open(stdout_filename, 'r') as f: 289 | stdout = f.read() 290 | 291 | # Read qsub stderr file 292 | stderr_filename = glob.glob(os.path.join(self.exp_path, 293 | '*.e{}'.format(run_id))) 294 | stderr = '' 295 | if len(stderr_filename) == 1: 296 | stderr_filename = stderr_filename[0] 297 | output_files.append(stderr_filename) 298 | with open(stderr_filename, 'r') as f: 299 | stderr = f.read() 300 | 301 | # Read the qsub id of the collate job from the stdout. 302 | # Payu puts this here. 303 | m = re.search(r'(\d+.gadi-pbs)\n', stdout) 304 | if m is None: 305 | print('Error: qsub id of collate job.', file=sys.stderr) 306 | return 3, stdout, stderr, output_files 307 | 308 | # Wait for the collate to complete. 309 | run_id = m.group(1) 310 | wait_for_qsub(run_id) 311 | 312 | # Return files created by qsub so caller can read or delete. 313 | collate_files = os.path.join(self.exp_path, '*.[oe]{}'.format(run_id)) 314 | output_files += glob.glob(collate_files) 315 | 316 | return 0, stdout, stderr, output_files 317 | 318 | def force_interactive_run(self): 319 | """ 320 | Already in a PBS session, run interactively 321 | """ 322 | 323 | # Change to experiment directory and run. 324 | try: 325 | os.chdir(self.exp_path) 326 | sp.check_output(['payu', 'sweep', '--lab', self.lab_path]) 327 | sp.check_output(['payu-run', '--lab', self.lab_path]) 328 | except sp.CalledProcessError as err: 329 | os.chdir(self.my_path) 330 | print('Error: call to payu run failed.', file=sys.stderr) 331 | return 1, None, None, None 332 | 333 | return 0, None, None, None 334 | 335 | def force_run(self): 336 | """ 337 | Always try to run. 338 | """ 339 | 340 | try: 341 | dont_care = os.environ['PBS_NODEFILE'] 342 | is_interactive = True 343 | except: 344 | is_interactive = False 345 | 346 | # Check whether this is an interactive PBS session. 347 | if is_interactive: 348 | ret, stdout, stderr, output_files = self.force_interactive_run() 349 | else: 350 | ret, stdout, stderr, output_files = self.force_qsub_run() 351 | 352 | return ret, stdout, stderr, output_files 353 | 354 | 355 | def build_and_run(self): 356 | 357 | exes, ret = self.build() 358 | assert ret == 0 359 | self.setup_for_programmatic_run(exes) 360 | self.force_run() 361 | 362 | 363 | def setup_exp_from_base(base_exp_name, new_exp_name): 364 | """ 365 | Create a new exp by copying the base config 366 | """ 367 | 368 | base_exp = ExpTestHelper(base_exp_name) 369 | 370 | new_exp_path = os.path.join(base_exp.control_path, new_exp_name) 371 | if os.path.exists(new_exp_path): 372 | shutil.rmtree(new_exp_path) 373 | shutil.copytree(base_exp.exp_path, new_exp_path, symlinks=True) 374 | 375 | new_exp = ExpTestHelper(new_exp_name) 376 | if os.path.exists(new_exp.archive): 377 | shutil.rmtree(new_exp.archive) 378 | 379 | try: 380 | os.remove(os.path.join(new_exp.control_path, 'archive')) 381 | except OSError: 382 | pass 383 | try: 384 | os.remove(os.path.join(new_exp.control_path, 'work')) 385 | except OSError: 386 | pass 387 | 388 | return new_exp 389 | 390 | 391 | def run_exp(exp_name, force=False): 392 | my_path = os.path.dirname(os.path.realpath(__file__)) 393 | 394 | helper = ExpTestHelper(exp_name) 395 | exes, ret = helper.build() 396 | assert ret == 0 397 | helper.setup_for_programmatic_run(exes) 398 | 399 | if force: 400 | ret, qso, qse, qsub_files = helper.force_run() 401 | else: 402 | ret, qso, qse, qsub_files = helper.run() 403 | 404 | assert ret == 0 405 | 406 | return helper 407 | -------------------------------------------------------------------------------- /test/load_dump.py: -------------------------------------------------------------------------------- 1 | 2 | import netCDF4 as nc 3 | 4 | 5 | def load(exp, routine, input_names, output_names): 6 | """ 7 | Load the input and output data for a particular unit test. 8 | """ 9 | 10 | inputs = {} 11 | outputs = {} 12 | 13 | for i in input_names: 14 | with nc.Dataset(routine + '-' + i) as f: 15 | inputs[i] = f.variables[i].data 16 | 17 | for o in output_names: 18 | with nc.Dataset(routine + '-' + o) as f: 19 | outputs[o] = f.variables[o].data 20 | 21 | return inputs, outputs 22 | 23 | 24 | def load_coupling_fields(exp, field_names): 25 | """ 26 | 27 | """ 28 | -------------------------------------------------------------------------------- /test/requirements_test.txt: -------------------------------------------------------------------------------- 1 | pytest 2 | pylint 3 | numpy 4 | f90nml 5 | netCDF4 6 | nose 7 | numba 8 | numpy 9 | pyyaml 10 | GitPython 11 | scipy 12 | -------------------------------------------------------------------------------- /test/test_bit_reproducibility.py: -------------------------------------------------------------------------------- 1 | 2 | from exp_test_helper import ExpTestHelper, setup_exp_from_base 3 | 4 | import pytest 5 | import f90nml 6 | import shutil 7 | import os 8 | import sys 9 | import re 10 | 11 | class TestBitReproducibility(): 12 | 13 | def checksums_to_list(self, filename): 14 | """ 15 | Look at each line an make a list of checksums 16 | """ 17 | 18 | regex_a = re.compile(r'\[chksum\]\s+.*\s+-?[0-9]+$') 19 | regex_b = re.compile(r'\[chksum\] Ice_ocean_boundary.*\s+-?[0-9]+$') 20 | l = [] 21 | with open(filename) as f: 22 | for line in f: 23 | m = regex_a.match(line) 24 | if m: 25 | l.append(line) 26 | else: 27 | m = regex_b.match(line) 28 | if m: 29 | l.append(line) 30 | return l 31 | 32 | @pytest.mark.slow 33 | def test_bit_repro_repeat(self): 34 | """ 35 | Test that a run reproduces saved checksums. 36 | """ 37 | 38 | exp_bit_repo1 = setup_exp_from_base('1deg_jra55_iaf', '1deg_jra55_iaf_bit_repo1') 39 | exp_bit_repo2 = setup_exp_from_base('1deg_jra55_iaf', '1deg_jra55_iaf_bit_repo2') 40 | 41 | # Reconfigure to a 1 day and do run 42 | for exp in [exp_bit_repo1, exp_bit_repo2]: 43 | with open(exp.accessom2_config) as f: 44 | nml = f90nml.read(f) 45 | 46 | nml['date_manager_nml']['restart_period'] = [0, 0, 86400] 47 | nml.write(exp.accessom2_config, force=True) 48 | exp.build_and_run() 49 | 50 | # Compare expected to produced. 51 | assert os.path.exists(exp_bit_repo1.accessom2_out_000) 52 | expected = self.checksums_to_list(exp_bit_repo1.accessom2_out_000) 53 | expected.sort() 54 | 55 | assert os.path.exists(exp_bit_repo2.accessom2_out_000) 56 | produced = self.checksums_to_list(exp_bit_repo2.accessom2_out_000) 57 | produced.sort() 58 | 59 | if produced != expected: 60 | with open('checksums-produced-test_bit_repo.txt', 'w') as f: 61 | f.write('\n'.join(produced)) 62 | with open('checksums-expected-test_bit_repo.txt', 'w') as f: 63 | f.write('\n'.join(expected)) 64 | 65 | assert len(produced) > 0 66 | assert len(produced) == len(expected) 67 | assert produced == expected 68 | 69 | @pytest.mark.slow 70 | def test_bit_repro_historical(self): 71 | """ 72 | Test that a run reproduces saved checksums. 73 | """ 74 | 75 | exp_bit_repo = setup_exp_from_base('1deg_jra55_iaf', '1deg_jra55_iaf_bit_repo') 76 | 77 | # Reconfigure to a 1 day and do run 78 | with open(exp_bit_repo.accessom2_config) as f: 79 | nml = f90nml.read(f) 80 | 81 | nml['date_manager_nml']['restart_period'] = [0, 0, 86400] 82 | nml.write(exp_bit_repo.accessom2_config, force=True) 83 | exp_bit_repo.build_and_run() 84 | 85 | assert os.path.exists(exp_bit_repo.accessom2_out_000) 86 | produced = self.checksums_to_list(exp_bit_repo.accessom2_out_000) 87 | 88 | # Compare expected to produced. 89 | test_stdout = os.path.join('checksums', '1deg_jra55_iaf-access-om2.out') 90 | assert os.path.exists(test_stdout) 91 | expected = self.checksums_to_list(test_stdout) 92 | 93 | wrong = 0 94 | assert len(produced) > 0 95 | for line in produced: 96 | if line not in expected: 97 | wrong = wrong + 1 98 | with open('checksums-produced-test_bit_repo.txt', 'w') as f: 99 | f.write('\n'.join(produced)) 100 | with open('checksums-expected-test_bit_repo.txt', 'w') as f: 101 | f.write('\n'.join(expected)) 102 | 103 | assert wrong == 0 104 | 105 | @pytest.mark.fast 106 | def test_restart_repro(self): 107 | """ 108 | Test that a run reproduces across restarts. 109 | """ 110 | 111 | # First do two short (1 day) runs. 112 | exp_2x1day = setup_exp_from_base('1deg_jra55_iaf', '1deg_jra55_iaf_2x1day') 113 | 114 | # Reconfigure to a 1 day run. 115 | with open(exp_2x1day.accessom2_config) as f: 116 | nml = f90nml.read(f) 117 | 118 | nml['date_manager_nml']['restart_period'] = [0, 0, 86400] 119 | nml.write(exp_2x1day.accessom2_config, force=True) 120 | 121 | # Don't use Redsea fix - this breaks reproducibility 122 | # https://github.com/COSIMA/access-om2/issues/124 123 | with open(exp_2x1day.ocean_config) as f: 124 | nml = f90nml.read(f) 125 | 126 | nml['auscom_ice_nml']['redsea_gulfbay_sfix'] = False 127 | nml.write(exp_2x1day.ocean_config, force=True) 128 | 129 | # Now run twice. 130 | exp_2x1day.build_and_run() 131 | exp_2x1day.force_run() 132 | 133 | # Now do a single 2 day run 134 | exp_2day = setup_exp_from_base('1deg_jra55_iaf', '1deg_jra55_iaf_2day') 135 | # Reconfigure 136 | with open(exp_2day.accessom2_config) as f: 137 | nml = f90nml.read(f) 138 | 139 | nml['date_manager_nml']['restart_period'] = [0, 0, 172800] 140 | nml.write(exp_2day.accessom2_config, force=True) 141 | 142 | # Don't use Redsea fix - this breaks reproducibility 143 | # https://github.com/COSIMA/access-om2/issues/124 144 | with open(exp_2day.ocean_config) as f: 145 | nml = f90nml.read(f) 146 | 147 | nml['auscom_ice_nml']['redsea_gulfbay_sfix'] = False 148 | nml.write(exp_2day.ocean_config, force=True) 149 | 150 | # Run once. 151 | exp_2day.build_and_run() 152 | 153 | # Now compare the output between our two short and one long run. 154 | two_shrt = self.checksums_to_list(exp_2x1day.accessom2_out_000) 155 | two_shrt = two_shrt + self.checksums_to_list(exp_2x1day.accessom2_out_001) 156 | 157 | one_long = self.checksums_to_list(exp_2day.accessom2_out_000) 158 | 159 | assert len(one_long) > 0 160 | for line in one_long: 161 | if line not in two_shrt: 162 | with open('checksums-two_short-test_restart_repo.txt', 'w') as f: 163 | f.write('\n'.join(two_shrt)) 164 | with open('checksums-one_long-test_restart_repo.txt', 'w') as f: 165 | f.write('\n'.join(one_long)) 166 | assert line in two_shrt 167 | 168 | # Additionally check that the temp and salt fields of the final restart 169 | # are identical 170 | -------------------------------------------------------------------------------- /test/test_build.py: -------------------------------------------------------------------------------- 1 | 2 | from exp_test_helper import ExpTestHelper 3 | 4 | class TestBuild(): 5 | 6 | def test_build_libaccessom2(self): 7 | helper = ExpTestHelper('1deg_jra55_ryf') 8 | exe, ret = helper.build_libaccessom2() 9 | assert ret == 0 10 | 11 | def test_build_1deg_cice(self): 12 | helper = ExpTestHelper('1deg_jra55_ryf') 13 | exe, ret = helper.build_cice() 14 | assert ret == 0 15 | 16 | def test_build_025deg_cice(self): 17 | helper = ExpTestHelper('025deg_jra55_ryf') 18 | exe, ret = helper.build_cice() 19 | assert ret == 0 20 | 21 | def test_build_01deg_cice(self): 22 | helper = ExpTestHelper('01deg_jra55_ryf') 23 | exe, ret = helper.build_cice() 24 | assert ret == 0 25 | 26 | def test_build_mom(self): 27 | helper = ExpTestHelper('1deg_jra55_ryf') 28 | exe, ret = helper.build_mom() 29 | assert ret == 0 30 | -------------------------------------------------------------------------------- /test/test_coupling_fields.py: -------------------------------------------------------------------------------- 1 | 2 | from __future__ import print_function 3 | 4 | import os 5 | import netCDF4 as nc 6 | 7 | from exp_test_helper import ExpTestHelper 8 | 9 | 10 | class TestCouplingFields(ExpTestHelper): 11 | 12 | def __init__(self): 13 | super(TestCouplingFields, self).__init__() 14 | 15 | def test_swflx(self): 16 | """ 17 | Compare short wave flux over a geographic area between low and hi res 18 | models. 19 | """ 20 | 21 | hi_paths = self.make_paths('cm_1440x1080-test') 22 | lo_paths = self.make_paths('cm_360x300-test') 23 | 24 | hi_fields = os.path.join(hi_paths['output'], 'ice', 25 | 'fields_a2i_in_ice.nc') 26 | lo_fields = os.path.join(lo_paths['output'], 'ice', 27 | 'fields_a2i_in_ice.nc') 28 | f_hi = nc.Dataset(hi_fields) 29 | f_hi.close() 30 | f_lo = nc.Dataset(lo_fields) 31 | f_lo.close() 32 | -------------------------------------------------------------------------------- /test/test_grids_match.py: -------------------------------------------------------------------------------- 1 | 2 | from exp_test_helper import ExpTestHelper 3 | import os 4 | import glob 5 | import netCDF4 as nc 6 | import numpy as np 7 | import pytest 8 | 9 | def find_nearest_index(array, value): 10 | return (np.abs(array - value)).argmin() 11 | 12 | class TestGridMatch(): 13 | """ 14 | Test that MOM and CICE grids match 15 | """ 16 | 17 | @pytest.mark.fast 18 | def test_mom_and_cice_output_grids(self): 19 | """ 20 | Compare mom output grid to cice output grid 21 | """ 22 | 23 | helper = ExpTestHelper('minimal_01deg_jra55_ryf_control') 24 | fo = nc.Dataset(os.path.join(helper.output000, 'ocean', 'ocean_grid.nc')) 25 | iceh = glob.glob(os.path.join(helper.archive, 'output*', 'ice', 26 | 'OUTPUT', 'iceh.*.nc')) 27 | fi = nc.Dataset(iceh[0]) 28 | 29 | fo_tmp = nc.Dataset(os.path.join(helper.mom_input, 'ocean_hgrid.nc')) 30 | fi_tmp = nc.Dataset(os.path.join(helper.cice_input, 'grid.nc')) 31 | 32 | xtmp = fo_tmp.variables['x'][:] 33 | ytmp = fo_tmp.variables['y'][:] 34 | 35 | xo_t = fo.variables['geolon_t'][:] 36 | xo_t[np.where(xo_t < 0)] += 360.0 37 | yo_t = fo.variables['geolat_t'][:] 38 | xo_u = fo.variables['geolon_c'][:] 39 | xo_u[np.where(xo_u < 0)] += 360.0 40 | yo_u = fo.variables['geolat_c'][:] 41 | 42 | xi_t = fi.variables['TLON'][:].astype('f') 43 | yi_t = fi.variables['TLAT'][:].astype('f') 44 | xi_u = fi.variables['ULON'][:].astype('f') 45 | yi_u = fi.variables['ULAT'][:].astype('f') 46 | 47 | mask = np.logical_or(xo_t.mask, xi_t.mask) 48 | assert np.ma.allclose(np.ma.array(xo_t, mask=mask), np.ma.array(xi_t, mask=mask), atol=0, rtol=1e-6) 49 | assert np.ma.allclose(np.ma.array(yo_t, mask=mask), np.ma.array(yi_t, mask=mask), atol=0, rtol=1e-6) 50 | #assert np.ma.allclose(np.ma.array(xo_u, mask=mask), np.ma.array(xi_u, mask=mask), atol=0, rtol=1e-6) 51 | #assert np.ma.allclose(np.ma.array(yo_u, mask=mask), np.ma.array(yi_u, mask=mask), atol=0, rtol=1e-6) 52 | 53 | dxo_t = fo.variables['dxt'][:] 54 | dyo_t = fo.variables['dyt'][:] 55 | dxo_u = fo.variables['dxu'][:] 56 | dyo_u = fo.variables['dyu'][:] 57 | 58 | dxi_t = fi.variables['dxt'][:] 59 | dyi_t = fi.variables['dyt'][:] 60 | dxi_u = fi.variables['dxu'][:] 61 | dyi_u = fi.variables['dyu'][:] 62 | 63 | mask = np.logical_or(dxo_t.mask, dxi_t.mask) 64 | assert np.ma.allclose(np.ma.array(dxo_t, mask=mask), np.ma.array(dxi_t, mask=mask), atol=0, rtol=1e-6) 65 | #assert np.ma.allclose(np.ma.array(dyo_t, mask=mask), np.ma.array(dyi_t, mask=mask), atol=0, rtol=1e-6) 66 | assert np.ma.allclose(np.ma.array(dxo_u, mask=mask), np.ma.array(dxi_u, mask=mask), atol=0, rtol=1e-6) 67 | #assert np.ma.allclose(np.ma.array(dyo_u, mask=mask), np.ma.array(dyi_u, mask=mask), atol=0, rtol=1e-6) 68 | 69 | areao_tmp = fo_tmp.variables['area'][:] 70 | 71 | areao_t = fo.variables['area_t'][:] 72 | areao_u = fo.variables['area_u'][:] 73 | 74 | areai_t = fi.variables['tarea'][:].astype('f') 75 | areai_u = fi.variables['uarea'][:].astype('f') 76 | 77 | # Area is difficult to compare because MOM uses dx*dy not the area from 78 | # ocean_hgrid.nc. We compare cells south of 65N. 79 | idx = find_nearest_index(yo_t[:, 0], 65.0) 80 | 81 | mask = np.logical_or(areao_t.mask, areai_t.mask) 82 | assert np.ma.allclose(np.ma.array(areao_t, mask=mask)[:idx, :], np.ma.array(areai_t, mask=mask)[:idx, :]) 83 | #assert np.ma.allclose(np.ma.array(areao_u, mask=mask)[:idx, :], np.ma.array(areai_u, mask=mask)[:idx, :]) 84 | 85 | import pdb 86 | pdb.set_trace() 87 | 88 | fo.close() 89 | fi.close() 90 | 91 | @pytest.mark.slow 92 | def test_mom_and_cice_input_grids(self): 93 | """ 94 | Test that the input grids match 95 | """ 96 | 97 | helper = ExpTestHelper('minimal_01deg_jra55_ryf_control') 98 | fo = nc.Dataset(os.path.join(helper.mom_input, 'ocean_hgrid.nc')) 99 | fi = nc.Dataset(os.path.join(helper.cice_input, 'grid.nc')) 100 | with nc.Dataset(os.path.join(helper.mom_input, 'ocean_mask.nc')) as f: 101 | mask = 1 - f.variables['mask'][:] 102 | 103 | x = fo.variables['x'][:, :] 104 | y = fo.variables['y'][:, :] 105 | 106 | # t-cell centres 107 | xo_t = x[1::2, 1::2] 108 | yo_t = y[1::2, 1::2] 109 | 110 | xi_t = np.rad2deg(fi.variables['tlon'][:]) 111 | yi_t = np.rad2deg(fi.variables['tlat'][:]) 112 | 113 | assert np.allclose(xi_t, xo_t, atol=0, rtol=1e-15) 114 | assert np.allclose(yi_t, yo_t, atol=0, rtol=1e-15) 115 | 116 | # u-cell centres 117 | xo_u = x[2::2, 2::2] 118 | yo_u = y[2::2, 2::2] 119 | 120 | xi_u = np.rad2deg(fi.variables['ulon'][:]) 121 | yi_u = np.rad2deg(fi.variables['ulat'][:]) 122 | 123 | #assert np.allclose(xi_u, xo_u, atol=0, rtol=1e-15) 124 | #assert np.allclose(yi_u, yo_u, atol=0, rtol=1e-15) 125 | 126 | #del x, y, xo_t, yo_t, xi_t, yi_t, xo_u, yo_u, xi_u, yi_u 127 | 128 | # cell area 129 | # Add up areas, going clockwise from bottom left. 130 | area = fo.variables['area'][:] 131 | areao_t = area[0::2, 0::2] + area[1::2, 0::2] + area[1::2, 1::2] + area[0::2, 1::2] 132 | 133 | # These need to wrap around the globe. Copy ocn_area and 134 | # add an extra column at the end. 135 | area_ext = np.append(area[:], area[:, 0:1], axis=1) 136 | areao_u = area_ext[0::2, 1::2] + area_ext[1::2, 1::2] + area_ext[1::2, 2::2] + area_ext[0::2, 2::2] 137 | 138 | areai_t = fi.variables['tarea'][:] 139 | areai_u = fi.variables['uarea'][:] 140 | 141 | assert np.array_equal(areao_t, areai_t) 142 | assert np.array_equal(areao_u, areai_u) 143 | 144 | # cell edge length 145 | # Grab the Northern and Eastern edge distances, not the centre distance, 146 | # this is what cice should be using. 147 | dx = fo.variables['dx'][:] 148 | dy = fo.variables['dy'][:] 149 | dxo_t = dx[2::2, ::2] + dx[2::2, 1::2] 150 | dyo_t = dy[::2, 2::2] + dy[1::2, 2::2] 151 | 152 | dxi_t = fi.variables['htn'][:] / 100 153 | dyi_t = fi.variables['hte'][:] / 100 154 | 155 | assert np.allclose(dxi_t, dxo_t, atol=0, rtol=1e-15) 156 | assert np.allclose(dyi_t, dyo_t, atol=0, rtol=1e-15) 157 | 158 | import pdb 159 | pdb.set_trace() 160 | 161 | # angle wrt East 162 | angleo_t = fo.variables['angle_dx'][1::2, 1::2] 163 | angleo_u = np.ma.array(fo.variables['angle_dx'][2::2, 2::2], mask=mask) 164 | 165 | anglei_t = np.rad2deg(fi.variables['angleT'][:]) 166 | anglei_u = np.ma.array(np.rad2deg(fi.variables['angle'][:]), mask=mask) 167 | 168 | #import pdb 169 | #pdb.set_trace() 170 | 171 | assert np.allclose(anglei_t, angleo_t, atol=0, rtol=1e-15) 172 | # Compare U using the land mask because MOM sets some land only longitudes to zero. 173 | assert np.ma.allclose(anglei_u, angleo_u, atol=0, rtol=1e-15) 174 | 175 | fo.close() 176 | fi.close() 177 | 178 | def test_mom_and_cice_mask(self): 179 | 180 | helper = ExpTestHelper('minimal_01deg_jra55_ryf_control') 181 | 182 | with nc.Dataset(os.path.join(helper.mom_input, 'ocean_mask.nc')) as f: 183 | omask = f.variables['mask'][:] 184 | 185 | with nc.Dataset(os.path.join(helper.cice_input, 'kmt.nc')) as f: 186 | imask = f.variables['mask'][:] 187 | 188 | import pdb 189 | pdb.set_trace() 190 | 191 | -------------------------------------------------------------------------------- /test/test_remapping_weights.py: -------------------------------------------------------------------------------- 1 | 2 | from __future__ import print_function 3 | 4 | from exp_test_helper import ExpTestHelper 5 | import os 6 | import numpy as np 7 | import numba 8 | import netCDF4 as nc 9 | import subprocess as sp 10 | import multiprocessing as mp 11 | 12 | EARTH_RADIUS = 6370997.0 13 | 14 | def calc_regridding_err(weights, src, dest): 15 | """ 16 | Calculate the regirdding error. 17 | """ 18 | 19 | with nc.Dataset(weights) as f: 20 | try: 21 | area_a = f.variables['area_a'][:] 22 | except KeyError as e: 23 | area_a = f.variables['src_grid_area'][:] 24 | area_a = area_a.reshape(src.shape[0], src.shape[1]) 25 | area_a = area_a*EARTH_RADIUS**2 26 | 27 | try: 28 | area_b = f.variables['area_b'][:] 29 | except KeyError as e: 30 | area_b = f.variables['dst_grid_area'][:] 31 | area_b = area_b.reshape(dest.shape[0], dest.shape[1]) 32 | area_b = area_b*EARTH_RADIUS**2 33 | 34 | try: 35 | frac_a = f.variables['frac_a'][:] 36 | except KeyError as e: 37 | frac_a = f.variables['src_grid_frac'][:] 38 | frac_a = frac_a.reshape(src.shape[0], src.shape[1]) 39 | 40 | try: 41 | frac_b = f.variables['frac_b'][:] 42 | except KeyError as e: 43 | frac_b = f.variables['dst_grid_frac'][:] 44 | frac_b = frac_b.reshape(dest.shape[0], dest.shape[1]) 45 | 46 | # Calculation of totals here. 47 | # http://www.earthsystemmodeling.org/esmf_releases/non_public/ESMF_5_3_0/ESMC_crefdoc/node3.html 48 | src_tot = np.sum(src[:, :] * area_a[:, :] * frac_a[:, :]) 49 | dest_tot = np.sum(dest[:, :] * area_b[:, :]) 50 | rel_err = abs(src_tot - dest_tot) / dest_tot 51 | 52 | return rel_err 53 | 54 | 55 | @numba.jit 56 | def apply_weights(src, dest_shape, n_s, n_b, row, col, s): 57 | """ 58 | Apply ESMF regirdding weights. 59 | """ 60 | 61 | dest = np.ndarray(dest_shape).flatten() 62 | dest[:] = 0.0 63 | src = src.flatten() 64 | 65 | for i in range(n_s): 66 | dest[row[i]-1] = dest[row[i]-1] + s[i]*src[col[i]-1] 67 | 68 | print('src.shape: {}'.format(src.shape)) 69 | print('n_s, n_b: {} {}'.format(n_s, n_b)) 70 | fstring = 'sum(row[:]) = {}, sum(col[:]) = {}, sum(S[:]) = {}' 71 | print(fstring.format(np.sum(row[:]), np.sum(col[:]), np.sum(s[:]))) 72 | 73 | return dest.reshape(dest_shape) 74 | 75 | 76 | def remap(src_data, weights, dest_shape): 77 | """ 78 | Regrid a 2d field and see how it looks. 79 | """ 80 | 81 | dest_data = np.ndarray(dest_shape) 82 | 83 | with nc.Dataset(weights) as wf: 84 | try: 85 | n_s = wf.dimensions['n_s'].size 86 | except KeyError as e: 87 | n_s = wf.dimensions['num_links'].size 88 | try: 89 | n_b = wf.dimensions['n_b'].size 90 | except KeyError as e: 91 | n_b = wf.dimensions['dst_grid_size'].size 92 | try: 93 | row = wf.variables['row'][:] 94 | except KeyError as e: 95 | row = wf.variables['dst_address'][:] 96 | try: 97 | col = wf.variables['col'][:] 98 | except KeyError as e: 99 | col = wf.variables['src_address'][:] 100 | 101 | s = wf.variables['S'][:] 102 | 103 | dest_data[:, :] = apply_weights(src_data[:, :], dest_data.shape, 104 | n_s, n_b, row, col, s) 105 | return dest_data 106 | 107 | 108 | class TestRemap(): 109 | def test_jra55_to_01deg(self): 110 | 111 | helper = ExpTestHelper('01deg_jra55_ryf') 112 | weights = os.path.join(helper.input_path, 'yatm_01deg', 113 | 'rmp_jrar_to_cict_CONSERV.nc') 114 | src = np.random.rand(1440, 720) 115 | dest = remap(src, weights, (3600, 2700)) 116 | 117 | rel_err = calc_regridding_err(weights, src, dest) 118 | print('relative error {}'.format(rel_err)) 119 | 120 | assert rel_err < 1e-14 121 | 122 | def test_jra55_to_1deg(self): 123 | pass 124 | 125 | def test_jra55_to_025deg(self): 126 | pass 127 | 128 | 129 | class TestCreateWeights(): 130 | """ 131 | Create weights and compare to existing. 132 | """ 133 | 134 | def test_build_esmf(self): 135 | """ 136 | Build ESMF 137 | """ 138 | 139 | helper = ExpTestHelper('01deg_jra55_ryf') 140 | 141 | contrib_dir = os.path.join(helper.lab_path, 'tools', 'contrib') 142 | os.chdir(contrib_dir) 143 | ret = sp.call('./build_esmf_on_raijin.sh') 144 | os.chdir(helper.lab_path) 145 | 146 | assert ret == 0 147 | assert os.path.exists(os.path.join(contrib_dir, 'bin', 'ESMF_RegridWeightGen')) 148 | 149 | def test_create_weights(self): 150 | """ 151 | Create weights 152 | """ 153 | 154 | helper = ExpTestHelper('01deg_jra55_ryf') 155 | 156 | # Build ESMF_RegridWeightGen if it doesn't already exist 157 | contrib_dir = os.path.join(helper.lab_path, 'tools', 'contrib') 158 | bpath = os.path.join(contrib_dir, 'bin', 'ESMF_RegridWeightGen') 159 | if not os.path.exists(bpath): 160 | self.test_build_esmf() 161 | 162 | cmd = os.path.join(os.getcwd(), 'tools', 'make_remap_weights.py') 163 | jra55_dir = '/g/data/ua8/JRA55-do/RYF/v1-3/' 164 | core_dir = os.path.join(helper.input_path, 'yatm_1deg') 165 | 166 | # Change to contrib bin dir to use ESMF_RegridWeightGen 167 | bin_dir = os.path.join(contrib_dir, 'bin') 168 | os.chdir(bin_dir) 169 | 170 | # We don't always test the more expensive weight creation. 171 | if (mp.cpu_count() // 2) < 8: 172 | ret = sp.call([cmd, helper.input_path, jra55_dir, core_dir, 173 | '--ocean', 'MOM1']) 174 | os.chdir(helper.lab_path) 175 | assert ret == 0 176 | ocn = ['MOM1'] 177 | else: 178 | ret = sp.call([cmd, helper.input_path, jra55_dir, core_dir]) 179 | os.chdir(helper.lab_path) 180 | assert ret == 0 181 | ocn = ['MOM1', 'MOM025', 'MOM01'] 182 | 183 | atm = ['JRA55', 'JRA55_runoff', 'CORE2', 'Daitren_runoff'] 184 | method = ['patch', 'conserve2nd'] 185 | 186 | for o in ocn: 187 | for a in atm: 188 | for m in method: 189 | filename = '{}_{}_{}.nc'.format(a, o, m) 190 | assert os.path.exists(os.path.join(bin_dir, filename)) 191 | -------------------------------------------------------------------------------- /test/test_run.py: -------------------------------------------------------------------------------- 1 | 2 | from exp_test_helper import run_exp 3 | 4 | import pytest 5 | 6 | 7 | class TestRun(): 8 | """ 9 | Run and check return code. 10 | """ 11 | 12 | @pytest.mark.fast 13 | def test_1deg_jra55_ryf_run(self): 14 | run_exp('1deg_jra55_ryf') 15 | 16 | @pytest.mark.slow 17 | def test_1deg_jra55_iaf_run(self): 18 | run_exp('1deg_jra55_iaf') 19 | 20 | @pytest.mark.slow 21 | def test_slow_run(self): 22 | run_exp('025deg_jra55_ryf') 23 | 24 | @pytest.mark.slow 25 | def test_slow_run_iaf(self): 26 | run_exp('025deg_jra55_iaf') 27 | -------------------------------------------------------------------------------- /test/test_startup.py: -------------------------------------------------------------------------------- 1 | 2 | from __future__ import print_function 3 | 4 | import netCDF4 as nc 5 | import os 6 | import filecmp 7 | from nose.plugins.attrib import attr 8 | 9 | from exp_test_helper import ExpTestHelper 10 | 11 | 12 | class TestStartUp(ExpTestHelper): 13 | 14 | def test_coupling_restarts_change(self): 15 | """ 16 | Check that the coupling restarts change between subsequent runs. If not 17 | they're not being regenerated properly. 18 | """ 19 | 20 | exps = ['cm_360x300-test', 'om_360x300-test'] 21 | cpl_restarts = ['a2i.nc', 'i2a.nc', 'o2i.nc', 'i2o.nc'] 22 | for e in exps: 23 | for r in cpl_restarts: 24 | run0_paths = self.make_paths(e, 0) 25 | run1_paths = self.make_paths(e, 1) 26 | 27 | self.get_most_recent_run_num(run0_paths['archive']) 28 | 29 | file0 = os.path.join(run0_paths['restart'], 'coupler', r) 30 | file1 = os.path.join(run1_paths['restart'], 'coupler', r) 31 | 32 | assert(not filecmp.cmp(file0, file1)) 33 | 34 | def test_coupling_restarts_loaded(self): 35 | """ 36 | Check that the fields on the first timestep are 37 | the same as the OASIS restarts. 38 | """ 39 | 40 | pass 41 | -------------------------------------------------------------------------------- /test/test_valgrind.py: -------------------------------------------------------------------------------- 1 | 2 | from __future__ import print_function 3 | 4 | import shutil 5 | import os 6 | 7 | from exp_test_helper import ExpTestHelper 8 | 9 | tests = {'om_360x300-valgrind': ('om'), 10 | 'om_1440x1080-valgrind': ('om')} 11 | 12 | 13 | class TestValgrind(ExpTestHelper): 14 | """ 15 | Run the model in valgrind. 16 | """ 17 | 18 | def __init__(self): 19 | super(TestValgrind, self).__init__() 20 | 21 | def pre_run_cleanup(self, exp): 22 | 23 | paths = self.make_paths(exp) 24 | 25 | try: 26 | shutil.rmtree(paths['archive']) 27 | os.remove(paths['archive_link']) 28 | except OSError as e: 29 | if not e.strerror == 'No such file or directory': 30 | raise e 31 | 32 | def check_run(self, key): 33 | 34 | print('############ Running {} ############'.format(key)) 35 | self.pre_run_cleanup(key) 36 | self.do_basic_access_run(key, model=tests[key][0]) 37 | 38 | # FIXME: check that valgrind does not find any problems. 39 | 40 | def test_runs(self): 41 | for k in tests.keys(): 42 | yield self.check_run, k 43 | -------------------------------------------------------------------------------- /test/util.py: -------------------------------------------------------------------------------- 1 | 2 | import os 3 | import time 4 | import subprocess as sp 5 | 6 | def wait_for_qsub(run_id): 7 | """ 8 | Wait for the qsub job to terminate. 9 | """ 10 | 11 | while True: 12 | time.sleep(10*60) 13 | try: 14 | qsub_out = sp.check_output(['qstat', run_id], stderr=sp.STDOUT) 15 | except sp.CalledProcessError as err: 16 | qsub_out = err.output 17 | 18 | qsub_out = qsub_out.decode() 19 | 20 | if 'Job has finished' in qsub_out: 21 | break 22 | 23 | 24 | def get_git_hash(src_dir): 25 | """ 26 | Get the git hash of src_dir. 27 | """ 28 | mydir = os.getcwd() 29 | os.chdir(src_dir) 30 | ghash = sp.check_output(['git', 'rev-parse', 'HEAD'])[:8] 31 | os.chdir(mydir) 32 | 33 | return ghash.decode('utf-8') 34 | -------------------------------------------------------------------------------- /test/valgrind_suppressions.txt: -------------------------------------------------------------------------------- 1 | { 2 | 3 | Memcheck:Cond 4 | fun:__intel_sse2_strcpy 5 | fun:for__open_proc 6 | fun:for__open_default 7 | fun:for_write_seq_fmt 8 | fun:ocean_momentum_source_mod_mp_rayleigh_damp_table_init_ 9 | fun:ocean_momentum_source_mod_mp_ocean_momentum_source_init_ 10 | fun:ocean_model_mod_mp_ocean_model_init_ 11 | fun:MAIN__ 12 | fun:main 13 | } 14 | { 15 | 16 | Memcheck:Cond 17 | fun:__intel_sse2_strcpy 18 | fun:for__open_proc 19 | fun:for__open_default 20 | fun:for_write_seq_fmt 21 | fun:sf_exch_ 22 | fun:sf_expl_ 23 | fun:bdy_layr_ 24 | fun:bl_intct_ 25 | fun:ni_bl_ctl_ 26 | fun:atmos_physics2_ 27 | fun:atm_step_ 28 | fun:u_model_ 29 | } 30 | { 31 | 32 | Memcheck:Cond 33 | fun:cvt_integer64_to_text 34 | fun:for__format_value 35 | fun:for_write_seq_fmt_xmit 36 | fun:for_write_seq_fmt 37 | fun:wrtwblog_ 38 | fun:routedbl_ 39 | fun:riv_rout_ 40 | fun:riv_intctl_ 41 | fun:atmos_physics2_ 42 | fun:atm_step_ 43 | fun:u_model_ 44 | fun:um_shell_ 45 | } 46 | { 47 | 48 | Memcheck:Cond 49 | fun:cvt_integer64_to_text 50 | fun:for__format_value 51 | fun:for_write_seq_fmt_xmit 52 | fun:wrtwblog_ 53 | fun:routedbl_ 54 | fun:riv_rout_ 55 | fun:riv_intctl_ 56 | fun:atmos_physics2_ 57 | fun:atm_step_ 58 | fun:u_model_ 59 | fun:um_shell_ 60 | fun:MAIN__ 61 | } 62 | { 63 | 64 | Memcheck:Addr16 65 | fun:kill_trailing 66 | fun:nf_inq_varid_ 67 | fun:ice_read_write_mp_ice_read_nc_ 68 | fun:ice_grid_mp_popgrid_nc_ 69 | fun:ice_grid_mp_init_grid2_ 70 | fun:cice_initmod_mp_cice_init_ 71 | fun:cice_initmod_mp_cice_initialize_ 72 | fun:MAIN__ 73 | fun:main 74 | } 75 | { 76 | 77 | Memcheck:Addr16 78 | fun:__intel_sse2_strlen 79 | fun:kill_trailing 80 | fun:nf_inq_dim_ 81 | fun:netcdf_mp_nf90_inquire_dimension_ 82 | fun:ice_read_write_mp_ice_read_nc_ 83 | fun:ice_grid_mp_popgrid_nc_ 84 | fun:ice_grid_mp_init_grid2_ 85 | fun:cice_initmod_mp_cice_init_ 86 | fun:cice_initmod_mp_cice_initialize_ 87 | fun:MAIN__ 88 | fun:main 89 | } 90 | { 91 | 92 | Memcheck:Addr16 93 | fun:kill_trailing 94 | fun:nf_inq_varid_ 95 | fun:ice_read_write_mp_ice_read_global_nc_ 96 | fun:ice_grid_mp_popgrid_nc_ 97 | fun:ice_grid_mp_init_grid2_ 98 | fun:cice_initmod_mp_cice_init_ 99 | fun:cice_initmod_mp_cice_initialize_ 100 | fun:MAIN__ 101 | fun:main 102 | } 103 | { 104 | 105 | Memcheck:Addr16 106 | fun:kill_trailing 107 | fun:nf_inq_varid_ 108 | fun:ice_read_write_mp_ice_read_nc_ 109 | fun:cpl_forcing_handler_mp_get_time0_sstsss_ 110 | fun:cice_initmod_mp_cice_init_ 111 | fun:cice_initmod_mp_cice_initialize_ 112 | fun:MAIN__ 113 | fun:main 114 | } 115 | { 116 | 117 | Memcheck:Addr16 118 | fun:kill_trailing 119 | fun:nf_open_ 120 | fun:netcdf_mp_nf90_open_ 121 | fun:ice_read_write_mp_ice_open_nc_ 122 | fun:cpl_forcing_handler_mp_get_restart_o2i_ 123 | fun:cice_initmod_mp_cice_init_ 124 | fun:cice_initmod_mp_cice_initialize_ 125 | fun:MAIN__ 126 | fun:main 127 | } 128 | { 129 | 130 | Memcheck:Addr16 131 | fun:kill_trailing 132 | fun:nf_inq_varid_ 133 | fun:ice_read_write_mp_ice_read_nc_ 134 | fun:cpl_forcing_handler_mp_get_restart_o2i_ 135 | fun:cice_initmod_mp_cice_init_ 136 | fun:cice_initmod_mp_cice_initialize_ 137 | fun:MAIN__ 138 | fun:main 139 | } 140 | { 141 | 142 | Memcheck:Addr16 143 | fun:__intel_sse2_strlen 144 | fun:kill_trailing 145 | fun:nf_create_ 146 | fun:netcdf_mp_nf90_create_ 147 | fun:dump_field_mp_setup_2d_ 148 | fun:dump_field_mp_dump_field_2d_ 149 | fun:cpl_interface_mp_from_atm_ 150 | fun:cice_runmod_mp_cice_run_ 151 | fun:MAIN__ 152 | fun:main 153 | } 154 | { 155 | 156 | Memcheck:Addr16 157 | fun:kill_trailing 158 | fun:nf_def_dim_ 159 | fun:dump_field_mp_setup_2d_ 160 | fun:dump_field_mp_dump_field_2d_ 161 | fun:cpl_interface_mp_from_atm_ 162 | fun:cice_runmod_mp_cice_run_ 163 | fun:MAIN__ 164 | fun:main 165 | } 166 | { 167 | 168 | Memcheck:Addr16 169 | fun:__intel_sse2_strlen 170 | fun:kill_trailing 171 | fun:nf_def_var_ 172 | fun:netcdf_mp_nf90_def_var_manydims_ 173 | fun:dump_field_mp_setup_2d_ 174 | fun:dump_field_mp_dump_field_2d_ 175 | fun:cpl_interface_mp_from_atm_ 176 | fun:cice_runmod_mp_cice_run_ 177 | fun:MAIN__ 178 | fun:main 179 | } 180 | { 181 | 182 | Memcheck:Addr16 183 | fun:kill_trailing 184 | fun:nf_open_ 185 | fun:netcdf_mp_nf90_open_ 186 | fun:ice_read_write_mp_ice_open_nc_ 187 | fun:cpl_forcing_handler_mp_get_restart_i2o_ 188 | fun:cice_runmod_mp_cice_run_ 189 | fun:MAIN__ 190 | fun:main 191 | } 192 | { 193 | 194 | Memcheck:Addr16 195 | fun:kill_trailing 196 | fun:nf_inq_varid_ 197 | fun:ice_read_write_mp_ice_read_nc_ 198 | fun:cpl_forcing_handler_mp_get_restart_i2o_ 199 | fun:cice_runmod_mp_cice_run_ 200 | fun:MAIN__ 201 | fun:main 202 | } 203 | { 204 | 205 | Memcheck:Cond 206 | fun:__intel_sse2_strcpy 207 | fun:for__open_proc 208 | fun:for__open_default 209 | fun:for_write_seq_lis 210 | fun:cpl_interface_mp_prism_init_ 211 | fun:cice_initmod_mp_cice_init_ 212 | fun:cice_initmod_mp_cice_initialize_ 213 | fun:MAIN__ 214 | fun:main 215 | } 216 | { 217 | 218 | Memcheck:Cond 219 | fun:__intel_sse2_strcpy 220 | fun:for__add_to_lf_table 221 | fun:for__open_proc 222 | fun:for__open_default 223 | fun:for_write_seq_lis 224 | fun:cpl_interface_mp_prism_init_ 225 | fun:cice_initmod_mp_cice_init_ 226 | fun:cice_initmod_mp_cice_initialize_ 227 | fun:MAIN__ 228 | fun:main 229 | } 230 | { 231 | 232 | Memcheck:Addr16 233 | fun:__intel_sse2_strlen 234 | fun:for__add_to_lf_table 235 | fun:for__open_proc 236 | fun:for__open_default 237 | fun:for_write_seq_fmt 238 | fun:mod_oasis_method_mp_oasis_init_comp_ 239 | fun:oasis3_atmos_init_mp_oasis3_um_init_ 240 | fun:um_shell_ 241 | fun:MAIN__ 242 | fun:main 243 | } 244 | { 245 | 246 | Memcheck:Addr16 247 | fun:__intel_sse2_strcpy 248 | fun:for__add_to_lf_table 249 | fun:for__open_proc 250 | fun:for__open_default 251 | fun:for_write_seq_fmt 252 | fun:mod_oasis_method_mp_oasis_init_comp_ 253 | fun:oasis3_atmos_init_mp_oasis3_um_init_ 254 | fun:um_shell_ 255 | fun:MAIN__ 256 | fun:main 257 | } 258 | { 259 | 260 | Memcheck:Param 261 | write(buf) 262 | obj:/lib64/libpthread-2.12.so 263 | fun:send_bytes 264 | fun:mca_oob_tcp_send_handler 265 | fun:opal_libevent2021_event_base_loop 266 | fun:orte_progress_thread_engine 267 | fun:start_thread 268 | fun:clone 269 | } 270 | { 271 | 272 | Memcheck:Value8 273 | obj:/plush/dugong/usr/lib64/libmlx4-rdmav2.so 274 | fun:udcm_process_messages 275 | fun:udcm_cq_event_dispatch 276 | fun:service_thread_start 277 | fun:start_thread 278 | fun:clone 279 | } 280 | { 281 | 282 | Memcheck:Cond 283 | obj:/plush/dugong/usr/lib64/libmlx4-rdmav2.so 284 | fun:udcm_process_messages 285 | fun:udcm_cq_event_dispatch 286 | fun:service_thread_start 287 | fun:start_thread 288 | fun:clone 289 | } 290 | { 291 | 292 | Memcheck:Value8 293 | obj:/plush/dugong/usr/lib64/libmlx4-rdmav2.so 294 | obj:/plush/dugong/usr/lib64/libmlx4-rdmav2.so 295 | fun:udcm_process_messages 296 | fun:udcm_cq_event_dispatch 297 | fun:service_thread_start 298 | fun:start_thread 299 | fun:clone 300 | } 301 | { 302 | 303 | Memcheck:Cond 304 | fun:ibv_create_ah 305 | fun:udcm_process_messages 306 | fun:udcm_cq_event_dispatch 307 | fun:service_thread_start 308 | fun:start_thread 309 | fun:clone 310 | } 311 | { 312 | 313 | Memcheck:Cond 314 | obj:/plush/dugong/usr/lib64/libmlx4-rdmav2.so 315 | fun:ibv_create_ah 316 | fun:udcm_process_messages 317 | fun:udcm_cq_event_dispatch 318 | fun:service_thread_start 319 | fun:start_thread 320 | fun:clone 321 | } 322 | { 323 | 324 | Memcheck:Cond 325 | obj:/plush/dugong/usr/lib64/libmlx4-rdmav2.so 326 | fun:udcm_post_send.clone.2 327 | fun:udcm_process_messages 328 | fun:udcm_cq_event_dispatch 329 | fun:service_thread_start 330 | fun:start_thread 331 | fun:clone 332 | } 333 | { 334 | 335 | Memcheck:Value8 336 | obj:/plush/dugong/usr/lib64/libmlx4-rdmav2.so 337 | fun:udcm_post_send.clone.2 338 | fun:udcm_process_messages 339 | fun:udcm_cq_event_dispatch 340 | fun:service_thread_start 341 | fun:start_thread 342 | fun:clone 343 | } 344 | { 345 | 346 | Memcheck:Value8 347 | obj:/plush/dugong/usr/lib64/libmlx4-rdmav2.so 348 | obj:/plush/dugong/usr/lib64/libmlx4-rdmav2.so 349 | fun:udcm_post_send.clone.2 350 | fun:udcm_process_messages 351 | fun:udcm_cq_event_dispatch 352 | fun:service_thread_start 353 | fun:start_thread 354 | fun:clone 355 | } 356 | { 357 | 358 | Memcheck:Cond 359 | fun:__intel_sse2_strcpy 360 | fun:for__open_proc 361 | fun:for__open_default 362 | fun:for_write_seq_lis 363 | fun:mod_oasis_sys_mp_oasis_unitget_ 364 | fun:mod_oasis_method_mp_oasis_init_comp_ 365 | fun:oasis3_atmos_init_mp_oasis3_um_init_ 366 | fun:um_shell_ 367 | fun:MAIN__ 368 | fun:main 369 | } 370 | { 371 | 372 | Memcheck:Cond 373 | fun:__intel_sse2_strcpy 374 | fun:for__add_to_lf_table 375 | fun:for__open_proc 376 | fun:for__open_default 377 | fun:for_write_seq_lis 378 | fun:mod_oasis_sys_mp_oasis_unitget_ 379 | fun:mod_oasis_method_mp_oasis_init_comp_ 380 | fun:oasis3_atmos_init_mp_oasis3_um_init_ 381 | fun:um_shell_ 382 | fun:MAIN__ 383 | fun:main 384 | } 385 | { 386 | 387 | Memcheck:Addr16 388 | fun:__intel_sse2_strlen 389 | fun:for__add_to_lf_table 390 | fun:for__open_proc 391 | fun:for_open 392 | fun:mod_oasis_method_mp_oasis_init_comp_ 393 | fun:oasis3_atmos_init_mp_oasis3_um_init_ 394 | fun:um_shell_ 395 | fun:MAIN__ 396 | fun:main 397 | } 398 | { 399 | 400 | Memcheck:Addr16 401 | fun:__intel_sse2_strcpy 402 | fun:for__add_to_lf_table 403 | fun:for__open_proc 404 | fun:for_open 405 | fun:mod_oasis_method_mp_oasis_init_comp_ 406 | fun:oasis3_atmos_init_mp_oasis3_um_init_ 407 | fun:um_shell_ 408 | fun:MAIN__ 409 | fun:main 410 | } 411 | { 412 | 413 | Memcheck:Cond 414 | fun:__intel_sse2_strcpy 415 | fun:for__open_proc 416 | fun:for_open 417 | fun:um_shell_ 418 | fun:MAIN__ 419 | fun:main 420 | } 421 | { 422 | 423 | Memcheck:Cond 424 | fun:__intel_sse2_strcpy 425 | fun:for__add_to_lf_table 426 | fun:for__open_proc 427 | fun:for_open 428 | fun:um_shell_ 429 | fun:MAIN__ 430 | fun:main 431 | } 432 | { 433 | 434 | Memcheck:Addr16 435 | fun:__intel_sse2_strlen 436 | fun:for__io_return 437 | fun:for_read_seq_nml 438 | fun:fms_mod_mp_nml_error_init_ 439 | fun:fms_mod_mp_fms_init_ 440 | fun:MAIN__ 441 | fun:main 442 | } 443 | { 444 | 445 | Memcheck:Addr16 446 | fun:__intel_sse2_strlen 447 | fun:for__add_to_lf_table 448 | fun:for__open_proc 449 | fun:for__open_default 450 | fun:for_write_seq_fmt 451 | fun:mod_oasis_method_mp_oasis_init_comp_ 452 | fun:mom_oasis3_interface_mod_mp_mom_prism_init_ 453 | fun:main_IP_external_coupler_mpi_init_ 454 | fun:MAIN__ 455 | fun:main 456 | } 457 | { 458 | 459 | Memcheck:Addr16 460 | fun:__intel_sse2_strcpy 461 | fun:for__add_to_lf_table 462 | fun:for__open_proc 463 | fun:for__open_default 464 | fun:for_write_seq_fmt 465 | fun:mod_oasis_method_mp_oasis_init_comp_ 466 | fun:mom_oasis3_interface_mod_mp_mom_prism_init_ 467 | fun:main_IP_external_coupler_mpi_init_ 468 | fun:MAIN__ 469 | fun:main 470 | } 471 | { 472 | 473 | Memcheck:Addr16 474 | fun:__intel_sse2_strlen 475 | fun:for__add_to_lf_table 476 | fun:for__open_proc 477 | fun:for_open 478 | fun:mod_oasis_namcouple_mp_oasis_namcouple_init_ 479 | fun:mod_oasis_method_mp_oasis_init_comp_ 480 | fun:mom_oasis3_interface_mod_mp_mom_prism_init_ 481 | fun:main_IP_external_coupler_mpi_init_ 482 | fun:MAIN__ 483 | fun:main 484 | } 485 | { 486 | 487 | Memcheck:Addr16 488 | fun:__intel_sse2_strcpy 489 | fun:for__add_to_lf_table 490 | fun:for__open_proc 491 | fun:for_open 492 | fun:mod_oasis_namcouple_mp_oasis_namcouple_init_ 493 | fun:mod_oasis_method_mp_oasis_init_comp_ 494 | fun:mom_oasis3_interface_mod_mp_mom_prism_init_ 495 | fun:main_IP_external_coupler_mpi_init_ 496 | fun:MAIN__ 497 | fun:main 498 | } 499 | { 500 | 501 | Memcheck:Addr16 502 | fun:__intel_sse2_strlen 503 | fun:for__io_return 504 | fun:for_read_seq_fmt 505 | fun:mod_oasis_namcouple_mp_inipar_alloc_ 506 | fun:mod_oasis_namcouple_mp_oasis_namcouple_init_ 507 | fun:mod_oasis_method_mp_oasis_init_comp_ 508 | fun:mom_oasis3_interface_mod_mp_mom_prism_init_ 509 | fun:main_IP_external_coupler_mpi_init_ 510 | fun:MAIN__ 511 | fun:main 512 | } 513 | { 514 | 515 | Memcheck:Addr16 516 | fun:__intel_sse2_strlen 517 | fun:for__io_return 518 | fun:for_read_seq_fmt 519 | fun:mod_oasis_namcouple_mp_inipar_ 520 | fun:mod_oasis_namcouple_mp_oasis_namcouple_init_ 521 | fun:mod_oasis_method_mp_oasis_init_comp_ 522 | fun:mom_oasis3_interface_mod_mp_mom_prism_init_ 523 | fun:main_IP_external_coupler_mpi_init_ 524 | fun:MAIN__ 525 | fun:main 526 | } 527 | { 528 | 529 | Memcheck:Addr16 530 | fun:__intel_sse2_strlen 531 | fun:for__add_to_lf_table 532 | fun:for__open_proc 533 | fun:for_open 534 | fun:mod_oasis_namcouple_mp_oasis_namcouple_init_ 535 | fun:mod_oasis_method_mp_oasis_init_comp_ 536 | fun:cpl_interface_mp_prism_init_ 537 | fun:cice_initmod_mp_cice_init_ 538 | fun:cice_initmod_mp_cice_initialize_ 539 | fun:MAIN__ 540 | fun:main 541 | } 542 | { 543 | 544 | Memcheck:Addr16 545 | fun:__intel_sse2_strcpy 546 | fun:for__add_to_lf_table 547 | fun:for__open_proc 548 | fun:for_open 549 | fun:mod_oasis_namcouple_mp_oasis_namcouple_init_ 550 | fun:mod_oasis_method_mp_oasis_init_comp_ 551 | fun:cpl_interface_mp_prism_init_ 552 | fun:cice_initmod_mp_cice_init_ 553 | fun:cice_initmod_mp_cice_initialize_ 554 | fun:MAIN__ 555 | fun:main 556 | } 557 | { 558 | 559 | Memcheck:Addr16 560 | fun:__intel_sse2_strlen 561 | fun:for__io_return 562 | fun:for_read_seq_fmt 563 | fun:mod_oasis_namcouple_mp_inipar_alloc_ 564 | fun:mod_oasis_namcouple_mp_oasis_namcouple_init_ 565 | fun:mod_oasis_method_mp_oasis_init_comp_ 566 | fun:cpl_interface_mp_prism_init_ 567 | fun:cice_initmod_mp_cice_init_ 568 | fun:cice_initmod_mp_cice_initialize_ 569 | fun:MAIN__ 570 | fun:main 571 | } 572 | { 573 | 574 | Memcheck:Addr16 575 | fun:__intel_sse2_strlen 576 | fun:for__io_return 577 | fun:for_read_seq_fmt 578 | fun:mod_oasis_namcouple_mp_inipar_ 579 | fun:mod_oasis_namcouple_mp_oasis_namcouple_init_ 580 | fun:mod_oasis_method_mp_oasis_init_comp_ 581 | fun:cpl_interface_mp_prism_init_ 582 | fun:cice_initmod_mp_cice_init_ 583 | fun:cice_initmod_mp_cice_initialize_ 584 | fun:MAIN__ 585 | fun:main 586 | } 587 | { 588 | 589 | Memcheck:Cond 590 | fun:__intel_sse2_strcpy 591 | fun:for__open_proc 592 | fun:for__open_default 593 | fun:for_write_seq_lis 594 | fun:mod_oasis_sys_mp_oasis_unitget_ 595 | fun:mod_oasis_method_mp_oasis_init_comp_ 596 | fun:mom_oasis3_interface_mod_mp_mom_prism_init_ 597 | fun:main_IP_external_coupler_mpi_init_ 598 | fun:MAIN__ 599 | fun:main 600 | } 601 | { 602 | 603 | Memcheck:Cond 604 | fun:__intel_sse2_strcpy 605 | fun:for__add_to_lf_table 606 | fun:for__open_proc 607 | fun:for__open_default 608 | fun:for_write_seq_lis 609 | fun:mod_oasis_sys_mp_oasis_unitget_ 610 | fun:mod_oasis_method_mp_oasis_init_comp_ 611 | fun:mom_oasis3_interface_mod_mp_mom_prism_init_ 612 | fun:main_IP_external_coupler_mpi_init_ 613 | fun:MAIN__ 614 | fun:main 615 | } 616 | { 617 | 618 | Memcheck:Cond 619 | fun:__intel_sse2_strcpy 620 | fun:for__open_proc 621 | fun:for__open_default 622 | fun:for_write_seq_lis 623 | fun:mod_oasis_sys_mp_oasis_unitget_ 624 | fun:mod_oasis_method_mp_oasis_init_comp_ 625 | fun:cpl_interface_mp_prism_init_ 626 | fun:cice_initmod_mp_cice_init_ 627 | fun:cice_initmod_mp_cice_initialize_ 628 | fun:MAIN__ 629 | fun:main 630 | } 631 | { 632 | 633 | Memcheck:Cond 634 | fun:__intel_sse2_strcpy 635 | fun:for__add_to_lf_table 636 | fun:for__open_proc 637 | fun:for__open_default 638 | fun:for_write_seq_lis 639 | fun:mod_oasis_sys_mp_oasis_unitget_ 640 | fun:mod_oasis_method_mp_oasis_init_comp_ 641 | fun:cpl_interface_mp_prism_init_ 642 | fun:cice_initmod_mp_cice_init_ 643 | fun:cice_initmod_mp_cice_initialize_ 644 | fun:MAIN__ 645 | fun:main 646 | } 647 | { 648 | 649 | Memcheck:Addr16 650 | fun:__intel_sse2_strlen 651 | fun:for__io_return 652 | fun:for_read_seq_fmt 653 | fun:mpp_mod_mp_get_ascii_file_num_lines_ 654 | fun:mpp_mod_mp_read_input_nml_ 655 | fun:mpp_mod_mp_mpp_init_ 656 | fun:fms_mod_mp_fms_init_ 657 | fun:MAIN__ 658 | fun:main 659 | } 660 | { 661 | 662 | Memcheck:Addr16 663 | fun:__intel_sse2_strlen 664 | fun:for__io_return 665 | fun:for_read_seq_fmt 666 | fun:mpp_mod_mp_read_ascii_file_ 667 | fun:mpp_mod_mp_read_input_nml_ 668 | fun:mpp_mod_mp_mpp_init_ 669 | fun:fms_mod_mp_fms_init_ 670 | fun:MAIN__ 671 | fun:main 672 | } 673 | { 674 | 675 | Memcheck:Addr16 676 | fun:__intel_sse2_strlen 677 | fun:for__io_return 678 | fun:for_read_seq_nml 679 | fun:mpp_mod_mp_mpp_init_ 680 | fun:fms_mod_mp_fms_init_ 681 | fun:MAIN__ 682 | fun:main 683 | } 684 | { 685 | 686 | Memcheck:Cond 687 | fun:__intel_sse2_strcpy 688 | fun:for__open_proc 689 | fun:for_open 690 | fun:mpp_mod_mp_mpp_init_ 691 | fun:fms_mod_mp_fms_init_ 692 | fun:MAIN__ 693 | fun:main 694 | } 695 | { 696 | 697 | Memcheck:Cond 698 | fun:__intel_sse2_strcpy 699 | fun:for__add_to_lf_table 700 | fun:for__open_proc 701 | fun:for_open 702 | fun:mpp_mod_mp_mpp_init_ 703 | fun:fms_mod_mp_fms_init_ 704 | fun:MAIN__ 705 | fun:main 706 | } 707 | { 708 | 709 | Memcheck:Addr16 710 | fun:__intel_sse2_strlen 711 | fun:for__io_return 712 | fun:for_read_seq_nml 713 | fun:ice_init_mp_input_data_ 714 | fun:cice_initmod_mp_cice_init_ 715 | fun:cice_initmod_mp_cice_initialize_ 716 | fun:MAIN__ 717 | fun:main 718 | } 719 | { 720 | 721 | Memcheck:Addr16 722 | fun:__intel_sse2_strlen 723 | fun:for__io_return 724 | fun:for_read_seq_nml 725 | fun:mpp_domains_mod_mp_mpp_domains_init_ 726 | fun:fms_mod_mp_fms_init_ 727 | fun:MAIN__ 728 | fun:main 729 | } 730 | { 731 | 732 | Memcheck:Addr16 733 | fun:__intel_sse2_strlen 734 | fun:for__io_return 735 | fun:for_read_seq_nml 736 | fun:mpp_io_mod_mp_mpp_io_init_ 737 | fun:fms_io_mod_mp_fms_io_init_ 738 | fun:fms_mod_mp_fms_init_ 739 | fun:MAIN__ 740 | fun:main 741 | } 742 | { 743 | 744 | Memcheck:Addr16 745 | fun:__intel_sse2_strlen 746 | fun:kill_trailing 747 | fun:nf__open_ 748 | fun:mpp_io_mod_mp_mpp_open_ 749 | fun:fms_io_mod_mp_get_file_unit_ 750 | fun:fms_io_mod_mp_field_exist_ 751 | fun:fms_io_mod_mp_fms_io_init_ 752 | fun:fms_mod_mp_fms_init_ 753 | fun:MAIN__ 754 | fun:main 755 | } 756 | { 757 | 758 | Memcheck:Addr16 759 | fun:kill_trailing 760 | fun:nf_inq_att_ 761 | fun:mpp_io_mod_mp_mpp_read_meta_ 762 | fun:mpp_io_mod_mp_mpp_open_ 763 | fun:fms_io_mod_mp_get_file_unit_ 764 | fun:fms_io_mod_mp_field_exist_ 765 | fun:fms_io_mod_mp_fms_io_init_ 766 | fun:fms_mod_mp_fms_init_ 767 | fun:MAIN__ 768 | fun:main 769 | } 770 | { 771 | 772 | Memcheck:Addr16 773 | fun:__intel_sse2_strlen 774 | fun:kill_trailing 775 | fun:nf_get_att_text_ 776 | fun:mpp_io_mod_mp_mpp_read_meta_ 777 | fun:mpp_io_mod_mp_mpp_open_ 778 | fun:fms_io_mod_mp_get_file_unit_ 779 | fun:fms_io_mod_mp_field_exist_ 780 | fun:fms_io_mod_mp_fms_io_init_ 781 | fun:fms_mod_mp_fms_init_ 782 | fun:MAIN__ 783 | fun:main 784 | } 785 | { 786 | 787 | Memcheck:Addr16 788 | fun:__intel_sse2_strlen 789 | fun:kill_trailing 790 | fun:nf_inq_attname_ 791 | fun:mpp_io_mod_mp_mpp_read_meta_ 792 | fun:mpp_io_mod_mp_mpp_open_ 793 | fun:fms_io_mod_mp_get_file_unit_ 794 | fun:fms_io_mod_mp_field_exist_ 795 | fun:fms_io_mod_mp_fms_io_init_ 796 | fun:fms_mod_mp_fms_init_ 797 | fun:MAIN__ 798 | fun:main 799 | } 800 | { 801 | 802 | Memcheck:Addr16 803 | fun:__intel_sse2_strlen 804 | fun:kill_trailing 805 | fun:nf_inq_att_ 806 | fun:mpp_io_mod_mp_mpp_read_meta_ 807 | fun:mpp_io_mod_mp_mpp_open_ 808 | fun:fms_io_mod_mp_get_file_unit_ 809 | fun:fms_io_mod_mp_field_exist_ 810 | fun:fms_io_mod_mp_fms_io_init_ 811 | fun:fms_mod_mp_fms_init_ 812 | fun:MAIN__ 813 | fun:main 814 | } 815 | { 816 | 817 | Memcheck:Addr16 818 | fun:__intel_sse2_strlen 819 | fun:kill_trailing 820 | fun:nf_get_att_real_ 821 | fun:mpp_io_mod_mp_mpp_read_meta_ 822 | fun:mpp_io_mod_mp_mpp_open_ 823 | fun:fms_io_mod_mp_get_file_unit_ 824 | fun:fms_io_mod_mp_field_exist_ 825 | fun:fms_io_mod_mp_fms_io_init_ 826 | fun:fms_mod_mp_fms_init_ 827 | fun:MAIN__ 828 | fun:main 829 | } 830 | { 831 | 832 | Memcheck:Addr16 833 | fun:__intel_sse2_strlen 834 | fun:kill_trailing 835 | fun:nf_inq_dim_ 836 | fun:mpp_io_mod_mp_mpp_read_meta_ 837 | fun:mpp_io_mod_mp_mpp_open_ 838 | fun:fms_io_mod_mp_get_file_unit_ 839 | fun:fms_io_mod_mp_field_exist_ 840 | fun:fms_io_mod_mp_fms_io_init_ 841 | fun:fms_mod_mp_fms_init_ 842 | fun:MAIN__ 843 | fun:main 844 | } 845 | { 846 | 847 | Memcheck:Addr16 848 | fun:__intel_sse2_strlen 849 | fun:kill_trailing 850 | fun:nf_inq_var_ 851 | fun:mpp_io_mod_mp_mpp_read_meta_ 852 | fun:mpp_io_mod_mp_mpp_open_ 853 | fun:fms_io_mod_mp_get_file_unit_ 854 | fun:fms_io_mod_mp_field_exist_ 855 | fun:fms_io_mod_mp_fms_io_init_ 856 | fun:fms_mod_mp_fms_init_ 857 | fun:MAIN__ 858 | fun:main 859 | } 860 | { 861 | 862 | Memcheck:Addr16 863 | fun:__intel_sse2_strlen 864 | fun:kill_trailing 865 | fun:nf_inq_dimid_ 866 | fun:mpp_io_mod_mp_mpp_read_meta_ 867 | fun:mpp_io_mod_mp_mpp_open_ 868 | fun:fms_io_mod_mp_get_file_unit_ 869 | fun:fms_io_mod_mp_field_exist_ 870 | fun:fms_io_mod_mp_fms_io_init_ 871 | fun:fms_mod_mp_fms_init_ 872 | fun:MAIN__ 873 | fun:main 874 | } 875 | { 876 | 877 | Memcheck:Addr16 878 | fun:kill_trailing 879 | fun:nf_get_att_text_ 880 | fun:mpp_io_mod_mp_mpp_read_meta_ 881 | fun:mpp_io_mod_mp_mpp_open_ 882 | fun:fms_io_mod_mp_get_file_unit_ 883 | fun:fms_io_mod_mp_field_exist_ 884 | fun:fms_io_mod_mp_fms_io_init_ 885 | fun:fms_mod_mp_fms_init_ 886 | fun:MAIN__ 887 | fun:main 888 | } 889 | { 890 | 891 | Memcheck:Addr16 892 | fun:__intel_sse2_strlen 893 | fun:kill_trailing 894 | fun:nf_open_ 895 | fun:netcdf_mp_nf90_open_ 896 | fun:ice_read_write_mp_ice_open_nc_ 897 | fun:ice_grid_mp_init_grid1_ 898 | fun:cice_initmod_mp_cice_init_ 899 | fun:cice_initmod_mp_cice_initialize_ 900 | fun:MAIN__ 901 | fun:main 902 | } 903 | { 904 | 905 | Memcheck:Addr16 906 | fun:kill_trailing 907 | fun:nf_inq_varid_ 908 | fun:ice_read_write_mp_ice_read_global_nc_ 909 | fun:ice_grid_mp_init_grid1_ 910 | fun:cice_initmod_mp_cice_init_ 911 | fun:cice_initmod_mp_cice_initialize_ 912 | fun:MAIN__ 913 | fun:main 914 | } 915 | { 916 | 917 | Memcheck:Addr16 918 | fun:__intel_sse2_strlen 919 | fun:kill_trailing 920 | fun:nf_inq_dim_ 921 | fun:netcdf_mp_nf90_inquire_dimension_ 922 | fun:ice_read_write_mp_ice_read_global_nc_ 923 | fun:ice_grid_mp_init_grid1_ 924 | fun:cice_initmod_mp_cice_init_ 925 | fun:cice_initmod_mp_cice_initialize_ 926 | fun:MAIN__ 927 | fun:main 928 | } 929 | { 930 | 931 | Memcheck:Addr16 932 | fun:__intel_sse2_strlen 933 | fun:for__io_return 934 | fun:for_read_seq_nml 935 | fun:time_interp_external_mod_mp_time_interp_external_init_ 936 | fun:MAIN__ 937 | fun:main 938 | } 939 | { 940 | 941 | Memcheck:Addr16 942 | fun:__intel_sse2_strlen 943 | fun:for__io_return 944 | fun:for_read_seq_nml 945 | fun:time_interp_mod_mp_time_interp_init_ 946 | fun:time_interp_external_mod_mp_time_interp_external_init_ 947 | fun:MAIN__ 948 | fun:main 949 | } 950 | { 951 | 952 | Memcheck:Addr16 953 | fun:__intel_sse2_strlen 954 | fun:for__io_return 955 | fun:for_read_seq_nml 956 | fun:ocean_parameters_mod_mp_ocean_parameters_init_ 957 | fun:ocean_model_mod_mp_ocean_model_init_ 958 | fun:MAIN__ 959 | fun:main 960 | } 961 | { 962 | 963 | Memcheck:Addr16 964 | fun:__intel_sse2_strlen 965 | fun:kill_trailing 966 | fun:nf__open_ 967 | fun:mpp_io_mod_mp_mpp_open_ 968 | fun:fms_io_mod_mp_get_global_att_value_text_ 969 | fun:ocean_grids_mod_mp_set_ocean_grid_size_ 970 | fun:ocean_model_mod_mp_ocean_model_init_ 971 | fun:MAIN__ 972 | fun:main 973 | } 974 | { 975 | 976 | Memcheck:Addr16 977 | fun:kill_trailing 978 | fun:nf_inq_att_ 979 | fun:mpp_io_mod_mp_mpp_read_meta_ 980 | fun:mpp_io_mod_mp_mpp_open_ 981 | fun:fms_io_mod_mp_get_global_att_value_text_ 982 | fun:ocean_grids_mod_mp_set_ocean_grid_size_ 983 | fun:ocean_model_mod_mp_ocean_model_init_ 984 | fun:MAIN__ 985 | fun:main 986 | } 987 | { 988 | 989 | Memcheck:Addr16 990 | fun:kill_trailing 991 | fun:nf_get_att_text_ 992 | fun:mpp_io_mod_mp_mpp_read_meta_ 993 | fun:mpp_io_mod_mp_mpp_open_ 994 | fun:fms_io_mod_mp_get_global_att_value_text_ 995 | fun:ocean_grids_mod_mp_set_ocean_grid_size_ 996 | fun:ocean_model_mod_mp_ocean_model_init_ 997 | fun:MAIN__ 998 | fun:main 999 | } 1000 | { 1001 | 1002 | Memcheck:Addr16 1003 | fun:__intel_sse2_strlen 1004 | fun:kill_trailing 1005 | fun:nf__open_ 1006 | fun:mpp_io_mod_mp_mpp_open_ 1007 | fun:fms_io_mod_mp_get_global_att_value_real_ 1008 | fun:ocean_grids_mod_mp_set_ocean_grid_size_ 1009 | fun:ocean_model_mod_mp_ocean_model_init_ 1010 | fun:MAIN__ 1011 | fun:main 1012 | } 1013 | { 1014 | 1015 | Memcheck:Addr16 1016 | fun:kill_trailing 1017 | fun:nf_inq_att_ 1018 | fun:mpp_io_mod_mp_mpp_read_meta_ 1019 | fun:mpp_io_mod_mp_mpp_open_ 1020 | fun:fms_io_mod_mp_get_global_att_value_real_ 1021 | fun:ocean_grids_mod_mp_set_ocean_grid_size_ 1022 | fun:ocean_model_mod_mp_ocean_model_init_ 1023 | fun:MAIN__ 1024 | fun:main 1025 | } 1026 | { 1027 | 1028 | Memcheck:Addr16 1029 | fun:kill_trailing 1030 | fun:nf_get_att_text_ 1031 | fun:mpp_io_mod_mp_mpp_read_meta_ 1032 | fun:mpp_io_mod_mp_mpp_open_ 1033 | fun:fms_io_mod_mp_get_global_att_value_real_ 1034 | fun:ocean_grids_mod_mp_set_ocean_grid_size_ 1035 | fun:ocean_model_mod_mp_ocean_model_init_ 1036 | fun:MAIN__ 1037 | fun:main 1038 | } 1039 | { 1040 | 1041 | Memcheck:Addr16 1042 | fun:__intel_sse2_strlen 1043 | fun:for__io_return 1044 | fun:for_read_seq_nml 1045 | fun:ocean_tracer_util_mod_mp_ocean_tracer_util_init_ 1046 | fun:ocean_model_mod_mp_ocean_model_init_ 1047 | fun:MAIN__ 1048 | fun:main 1049 | } 1050 | { 1051 | 1052 | Memcheck:Addr16 1053 | fun:__intel_sse2_strlen 1054 | fun:for__io_return 1055 | fun:for_read_seq_nml 1056 | fun:ocean_operators_mod_mp_ocean_operators_init_ 1057 | fun:ocean_model_mod_mp_ocean_model_init_ 1058 | fun:MAIN__ 1059 | fun:main 1060 | } 1061 | { 1062 | 1063 | Memcheck:Addr16 1064 | fun:__intel_sse2_strlen 1065 | fun:kill_trailing 1066 | fun:nf_inq_varid_ 1067 | fun:mpp_io_mod_mp_mpp_read_meta_ 1068 | fun:mpp_io_mod_mp_mpp_open_ 1069 | fun:fms_io_mod_mp_get_file_unit_ 1070 | fun:fms_io_mod_mp_field_exist_ 1071 | fun:ocean_tracer_mod_mp_ocean_prog_tracer_init_ 1072 | fun:ocean_model_mod_mp_ocean_model_init_ 1073 | fun:MAIN__ 1074 | fun:main 1075 | } 1076 | { 1077 | 1078 | Memcheck:Addr16 1079 | fun:kill_trailing 1080 | fun:nf_get_att_double_ 1081 | fun:mpp_io_mod_mp_mpp_read_meta_ 1082 | fun:mpp_io_mod_mp_mpp_open_ 1083 | fun:fms_io_mod_mp_get_file_unit_ 1084 | fun:fms_io_mod_mp_field_exist_ 1085 | fun:ocean_tracer_mod_mp_ocean_prog_tracer_init_ 1086 | fun:ocean_model_mod_mp_ocean_model_init_ 1087 | fun:MAIN__ 1088 | fun:main 1089 | } 1090 | { 1091 | 1092 | Memcheck:Addr16 1093 | fun:kill_trailing 1094 | fun:nf_get_att_real_ 1095 | fun:mpp_io_mod_mp_mpp_read_meta_ 1096 | fun:mpp_io_mod_mp_mpp_open_ 1097 | fun:fms_io_mod_mp_get_file_unit_ 1098 | fun:fms_io_mod_mp_field_exist_ 1099 | fun:ocean_tracer_mod_mp_ocean_prog_tracer_init_ 1100 | fun:ocean_model_mod_mp_ocean_model_init_ 1101 | fun:MAIN__ 1102 | fun:main 1103 | } 1104 | { 1105 | 1106 | Memcheck:Addr16 1107 | fun:__intel_sse2_strlen 1108 | fun:kill_trailing 1109 | fun:nf__open_ 1110 | fun:mpp_io_mod_mp_mpp_open_ 1111 | fun:fms_io_mod_mp_restore_state_one_field_ 1112 | fun:ocean_tracer_mod_mp_ocean_prog_tracer_init_ 1113 | fun:ocean_model_mod_mp_ocean_model_init_ 1114 | fun:MAIN__ 1115 | fun:main 1116 | } 1117 | { 1118 | 1119 | Memcheck:Addr16 1120 | fun:__intel_sse2_strlen 1121 | fun:kill_trailing 1122 | fun:nf_inq_dim_ 1123 | fun:mpp_io_mod_mp_mpp_read_meta_ 1124 | fun:mpp_io_mod_mp_mpp_open_ 1125 | fun:fms_io_mod_mp_restore_state_one_field_ 1126 | fun:ocean_tracer_mod_mp_ocean_prog_tracer_init_ 1127 | fun:ocean_model_mod_mp_ocean_model_init_ 1128 | fun:MAIN__ 1129 | fun:main 1130 | } 1131 | { 1132 | 1133 | Memcheck:Addr16 1134 | fun:kill_trailing 1135 | fun:nf_inq_att_ 1136 | fun:mpp_io_mod_mp_mpp_read_meta_ 1137 | fun:mpp_io_mod_mp_mpp_open_ 1138 | fun:fms_io_mod_mp_restore_state_one_field_ 1139 | fun:ocean_tracer_mod_mp_ocean_prog_tracer_init_ 1140 | fun:ocean_model_mod_mp_ocean_model_init_ 1141 | fun:MAIN__ 1142 | fun:main 1143 | } 1144 | { 1145 | 1146 | Memcheck:Addr16 1147 | fun:kill_trailing 1148 | fun:nf_get_att_text_ 1149 | fun:mpp_io_mod_mp_mpp_read_meta_ 1150 | fun:mpp_io_mod_mp_mpp_open_ 1151 | fun:fms_io_mod_mp_restore_state_one_field_ 1152 | fun:ocean_tracer_mod_mp_ocean_prog_tracer_init_ 1153 | fun:ocean_model_mod_mp_ocean_model_init_ 1154 | fun:MAIN__ 1155 | fun:main 1156 | } 1157 | { 1158 | 1159 | Memcheck:Addr16 1160 | fun:kill_trailing 1161 | fun:nf_get_att_double_ 1162 | fun:mpp_io_mod_mp_mpp_read_meta_ 1163 | fun:mpp_io_mod_mp_mpp_open_ 1164 | fun:fms_io_mod_mp_restore_state_one_field_ 1165 | fun:ocean_tracer_mod_mp_ocean_prog_tracer_init_ 1166 | fun:ocean_model_mod_mp_ocean_model_init_ 1167 | fun:MAIN__ 1168 | fun:main 1169 | } 1170 | { 1171 | 1172 | Memcheck:Addr16 1173 | fun:kill_trailing 1174 | fun:nf_get_att_real_ 1175 | fun:mpp_io_mod_mp_mpp_read_meta_ 1176 | fun:mpp_io_mod_mp_mpp_open_ 1177 | fun:fms_io_mod_mp_restore_state_one_field_ 1178 | fun:ocean_tracer_mod_mp_ocean_prog_tracer_init_ 1179 | fun:ocean_model_mod_mp_ocean_model_init_ 1180 | fun:MAIN__ 1181 | fun:main 1182 | } 1183 | { 1184 | 1185 | Memcheck:Addr16 1186 | fun:__intel_sse2_strlen 1187 | fun:for__io_return 1188 | fun:for_read_seq_nml 1189 | fun:ocean_blob_mod_mp_ocean_blob_init_ 1190 | fun:ocean_model_mod_mp_ocean_model_init_ 1191 | fun:MAIN__ 1192 | fun:main 1193 | } 1194 | { 1195 | 1196 | Memcheck:Addr16 1197 | fun:__intel_sse2_strlen 1198 | fun:for__io_return 1199 | fun:for_read_seq_nml 1200 | fun:ocean_vert_util_mod_mp_ocean_vert_util_init_ 1201 | fun:ocean_vert_mix_mod_mp_ocean_vert_mix_init_ 1202 | fun:ocean_model_mod_mp_ocean_model_init_ 1203 | fun:MAIN__ 1204 | fun:main 1205 | } 1206 | { 1207 | 1208 | Memcheck:Addr16 1209 | fun:kill_trailing 1210 | fun:nf_get_att_double_ 1211 | fun:mpp_io_mod_mp_mpp_read_meta_ 1212 | fun:mpp_io_mod_mp_mpp_open_ 1213 | fun:fms_io_mod_mp_get_file_unit_ 1214 | fun:fms_io_mod_mp_read_data_3d_new_ 1215 | fun:fms_io_mod_mp_read_data_2d_new_ 1216 | fun:ocean_vert_tidal_mod_mp_ocean_vert_tidal_init_ 1217 | fun:ocean_vert_mix_mod_mp_ocean_vert_mix_init_ 1218 | fun:ocean_model_mod_mp_ocean_model_init_ 1219 | fun:MAIN__ 1220 | fun:main 1221 | } 1222 | { 1223 | 1224 | Memcheck:Addr16 1225 | fun:__intel_sse2_strlen 1226 | fun:for__io_return 1227 | fun:for_read_seq_nml 1228 | fun:ocean_vert_kpp_mom4p1_mod_mp_ocean_vert_kpp_mom4p1_init_ 1229 | fun:ocean_vert_mix_mod_mp_ocean_vert_mix_init_ 1230 | fun:ocean_model_mod_mp_ocean_model_init_ 1231 | fun:MAIN__ 1232 | fun:main 1233 | } 1234 | { 1235 | 1236 | Memcheck:Addr16 1237 | fun:__intel_sse2_strlen 1238 | fun:for__io_return 1239 | fun:for_read_seq_nml 1240 | fun:ocean_nphysics_new_mod_mp_ocean_nphysics_new_init_ 1241 | fun:ocean_model_mod_mp_ocean_model_init_ 1242 | fun:MAIN__ 1243 | fun:main 1244 | } 1245 | { 1246 | 1247 | Memcheck:Addr16 1248 | fun:__intel_sse2_strlen 1249 | fun:for__io_return 1250 | fun:for_read_seq_nml 1251 | fun:ocean_nphysics_util_new_mod_mp_ocean_nphysics_util_new_init_ 1252 | fun:ocean_nphysics_new_mod_mp_ocean_nphysics_new_init_ 1253 | fun:ocean_model_mod_mp_ocean_model_init_ 1254 | fun:MAIN__ 1255 | fun:main 1256 | } 1257 | { 1258 | 1259 | Memcheck:Addr16 1260 | fun:__intel_sse2_strlen 1261 | fun:kill_trailing 1262 | fun:nf__open_ 1263 | fun:mpp_io_mod_mp_mpp_open_ 1264 | fun:time_interp_external_mod_mp_init_external_field_ 1265 | fun:ocean_sbc_mod_mp_ocean_sbc_init_ 1266 | fun:ocean_model_mod_mp_ocean_model_init_ 1267 | fun:MAIN__ 1268 | fun:main 1269 | } 1270 | { 1271 | 1272 | Memcheck:Addr16 1273 | fun:kill_trailing 1274 | fun:nf_inq_att_ 1275 | fun:mpp_io_mod_mp_mpp_read_meta_ 1276 | fun:mpp_io_mod_mp_mpp_open_ 1277 | fun:time_interp_external_mod_mp_init_external_field_ 1278 | fun:ocean_sbc_mod_mp_ocean_sbc_init_ 1279 | fun:ocean_model_mod_mp_ocean_model_init_ 1280 | fun:MAIN__ 1281 | fun:main 1282 | } 1283 | { 1284 | 1285 | Memcheck:Addr16 1286 | fun:kill_trailing 1287 | fun:nf_get_att_text_ 1288 | fun:mpp_io_mod_mp_mpp_read_meta_ 1289 | fun:mpp_io_mod_mp_mpp_open_ 1290 | fun:time_interp_external_mod_mp_init_external_field_ 1291 | fun:ocean_sbc_mod_mp_ocean_sbc_init_ 1292 | fun:ocean_model_mod_mp_ocean_model_init_ 1293 | fun:MAIN__ 1294 | fun:main 1295 | } 1296 | { 1297 | 1298 | Memcheck:Addr16 1299 | fun:kill_trailing 1300 | fun:nf_get_att_double_ 1301 | fun:mpp_io_mod_mp_mpp_read_meta_ 1302 | fun:mpp_io_mod_mp_mpp_open_ 1303 | fun:time_interp_external_mod_mp_init_external_field_ 1304 | fun:ocean_sbc_mod_mp_ocean_sbc_init_ 1305 | fun:ocean_model_mod_mp_ocean_model_init_ 1306 | fun:MAIN__ 1307 | fun:main 1308 | } 1309 | { 1310 | 1311 | Memcheck:Addr16 1312 | fun:__intel_sse2_strlen 1313 | fun:kill_trailing 1314 | fun:nf_get_att_text_ 1315 | fun:mpp_io_mod_mp_mpp_read_meta_ 1316 | fun:mpp_io_mod_mp_mpp_open_ 1317 | fun:time_interp_external_mod_mp_init_external_field_ 1318 | fun:ocean_sbc_mod_mp_ocean_sbc_init_ 1319 | fun:ocean_model_mod_mp_ocean_model_init_ 1320 | fun:MAIN__ 1321 | fun:main 1322 | } 1323 | { 1324 | 1325 | Memcheck:Addr16 1326 | fun:__intel_sse2_strlen 1327 | fun:for__io_return 1328 | fun:for_read_seq_nml 1329 | fun:get_cal_time_mod_mp_get_cal_time_ 1330 | fun:time_interp_external_mod_mp_init_external_field_ 1331 | fun:ocean_sbc_mod_mp_ocean_sbc_init_ 1332 | fun:ocean_model_mod_mp_ocean_model_init_ 1333 | fun:MAIN__ 1334 | fun:main 1335 | } 1336 | { 1337 | 1338 | Memcheck:Addr16 1339 | fun:__intel_sse2_strlen 1340 | fun:for__io_return 1341 | fun:for_read_seq_nml 1342 | fun:ocean_wave_mod_mp_ocean_wave_init_ 1343 | fun:ocean_model_mod_mp_ocean_model_init_ 1344 | fun:MAIN__ 1345 | fun:main 1346 | } 1347 | { 1348 | 1349 | Memcheck:Addr16 1350 | fun:__intel_sse2_strlen 1351 | fun:for__io_return 1352 | fun:for_read_seq_nml 1353 | fun:horiz_interp_mod_mp_horiz_interp_init_ 1354 | fun:data_override_mod_mp_data_override_init_ 1355 | fun:MAIN__ 1356 | fun:main 1357 | } 1358 | { 1359 | 1360 | Memcheck:Addr16 1361 | fun:__intel_sse2_strlen 1362 | fun:for__io_return 1363 | fun:for_read_seq_nml 1364 | fun:horiz_interp_spherical_mod_mp_horiz_interp_spherical_init_ 1365 | fun:horiz_interp_mod_mp_horiz_interp_init_ 1366 | fun:data_override_mod_mp_data_override_init_ 1367 | fun:MAIN__ 1368 | fun:main 1369 | } 1370 | { 1371 | 1372 | Memcheck:Addr16 1373 | fun:__intel_sse2_strlen 1374 | fun:kill_trailing 1375 | fun:nf_open_ 1376 | fun:netcdf_mp_nf90_open_ 1377 | fun:mod_oasis_coupler_mp_oasis_coupler_setup_ 1378 | fun:mod_oasis_method_mp_oasis_enddef_ 1379 | fun:cpl_interface_mp_init_cpl_ 1380 | fun:cice_initmod_mp_cice_init_ 1381 | fun:cice_initmod_mp_cice_initialize_ 1382 | fun:MAIN__ 1383 | fun:main 1384 | } 1385 | { 1386 | 1387 | Memcheck:Addr16 1388 | fun:kill_trailing 1389 | fun:nf_inq_dimid_ 1390 | fun:mod_oasis_coupler_mp_oasis_coupler_setup_ 1391 | fun:mod_oasis_method_mp_oasis_enddef_ 1392 | fun:cpl_interface_mp_init_cpl_ 1393 | fun:cice_initmod_mp_cice_init_ 1394 | fun:cice_initmod_mp_cice_initialize_ 1395 | fun:MAIN__ 1396 | fun:main 1397 | } 1398 | { 1399 | 1400 | Memcheck:Addr16 1401 | fun:__intel_sse2_strlen 1402 | fun:kill_trailing 1403 | fun:nf_inq_dim_ 1404 | fun:netcdf_mp_nf90_inquire_dimension_ 1405 | fun:mod_oasis_coupler_mp_oasis_coupler_setup_ 1406 | fun:mod_oasis_method_mp_oasis_enddef_ 1407 | fun:cpl_interface_mp_init_cpl_ 1408 | fun:cice_initmod_mp_cice_init_ 1409 | fun:cice_initmod_mp_cice_initialize_ 1410 | fun:MAIN__ 1411 | fun:main 1412 | } 1413 | { 1414 | 1415 | Memcheck:Addr16 1416 | fun:__intel_sse2_strlen 1417 | fun:kill_trailing 1418 | fun:nf_open_ 1419 | fun:netcdf_mp_nf90_open_ 1420 | fun:mod_oasis_coupler_mp_oasis_coupler_smatreaddnc_ 1421 | fun:mod_oasis_coupler_mp_oasis_coupler_setup_ 1422 | fun:mod_oasis_method_mp_oasis_enddef_ 1423 | fun:cpl_interface_mp_init_cpl_ 1424 | fun:cice_initmod_mp_cice_init_ 1425 | fun:cice_initmod_mp_cice_initialize_ 1426 | fun:MAIN__ 1427 | fun:main 1428 | } 1429 | { 1430 | 1431 | Memcheck:Addr16 1432 | fun:kill_trailing 1433 | fun:nf_inq_dimid_ 1434 | fun:mod_oasis_coupler_mp_oasis_coupler_smatreaddnc_ 1435 | fun:mod_oasis_coupler_mp_oasis_coupler_setup_ 1436 | fun:mod_oasis_method_mp_oasis_enddef_ 1437 | fun:cpl_interface_mp_init_cpl_ 1438 | fun:cice_initmod_mp_cice_init_ 1439 | fun:cice_initmod_mp_cice_initialize_ 1440 | fun:MAIN__ 1441 | fun:main 1442 | } 1443 | { 1444 | 1445 | Memcheck:Addr16 1446 | fun:__intel_sse2_strlen 1447 | fun:kill_trailing 1448 | fun:nf_inq_dim_ 1449 | fun:netcdf_mp_nf90_inquire_dimension_ 1450 | fun:mod_oasis_coupler_mp_oasis_coupler_smatreaddnc_ 1451 | fun:mod_oasis_coupler_mp_oasis_coupler_setup_ 1452 | fun:mod_oasis_method_mp_oasis_enddef_ 1453 | fun:cpl_interface_mp_init_cpl_ 1454 | fun:cice_initmod_mp_cice_init_ 1455 | fun:cice_initmod_mp_cice_initialize_ 1456 | fun:MAIN__ 1457 | fun:main 1458 | } 1459 | { 1460 | 1461 | Memcheck:Addr16 1462 | fun:kill_trailing 1463 | fun:nf_inq_varid_ 1464 | fun:mod_oasis_coupler_mp_oasis_coupler_smatreaddnc_ 1465 | fun:mod_oasis_coupler_mp_oasis_coupler_setup_ 1466 | fun:mod_oasis_method_mp_oasis_enddef_ 1467 | fun:cpl_interface_mp_init_cpl_ 1468 | fun:cice_initmod_mp_cice_init_ 1469 | fun:cice_initmod_mp_cice_initialize_ 1470 | fun:MAIN__ 1471 | fun:main 1472 | } 1473 | { 1474 | 1475 | Memcheck:Addr16 1476 | fun:__intel_sse2_strlen 1477 | fun:kill_trailing 1478 | fun:nf_open_ 1479 | fun:netcdf_mp_nf90_open_ 1480 | fun:mod_oasis_coupler_mp_oasis_coupler_setup_ 1481 | fun:mod_oasis_method_mp_oasis_enddef_ 1482 | fun:cpl_interfaces_mp_init_cpl_ 1483 | fun:MAIN__ 1484 | fun:main 1485 | } 1486 | { 1487 | 1488 | Memcheck:Addr16 1489 | fun:kill_trailing 1490 | fun:nf_inq_dimid_ 1491 | fun:mod_oasis_coupler_mp_oasis_coupler_setup_ 1492 | fun:mod_oasis_method_mp_oasis_enddef_ 1493 | fun:cpl_interfaces_mp_init_cpl_ 1494 | fun:MAIN__ 1495 | fun:main 1496 | } 1497 | { 1498 | 1499 | Memcheck:Addr16 1500 | fun:__intel_sse2_strlen 1501 | fun:kill_trailing 1502 | fun:nf_open_ 1503 | fun:netcdf_mp_nf90_open_ 1504 | fun:mod_oasis_coupler_mp_oasis_coupler_smatreaddnc_ 1505 | fun:mod_oasis_coupler_mp_oasis_coupler_setup_ 1506 | fun:mod_oasis_method_mp_oasis_enddef_ 1507 | fun:cpl_interfaces_mp_init_cpl_ 1508 | fun:MAIN__ 1509 | fun:main 1510 | } 1511 | { 1512 | 1513 | Memcheck:Addr16 1514 | fun:kill_trailing 1515 | fun:nf_inq_dimid_ 1516 | fun:mod_oasis_coupler_mp_oasis_coupler_smatreaddnc_ 1517 | fun:mod_oasis_coupler_mp_oasis_coupler_setup_ 1518 | fun:mod_oasis_method_mp_oasis_enddef_ 1519 | fun:cpl_interfaces_mp_init_cpl_ 1520 | fun:MAIN__ 1521 | fun:main 1522 | } 1523 | { 1524 | 1525 | Memcheck:Addr16 1526 | fun:__intel_sse2_strlen 1527 | fun:kill_trailing 1528 | fun:nf_inq_dim_ 1529 | fun:netcdf_mp_nf90_inquire_dimension_ 1530 | fun:mod_oasis_coupler_mp_oasis_coupler_smatreaddnc_ 1531 | fun:mod_oasis_coupler_mp_oasis_coupler_setup_ 1532 | fun:mod_oasis_method_mp_oasis_enddef_ 1533 | fun:cpl_interfaces_mp_init_cpl_ 1534 | fun:MAIN__ 1535 | fun:main 1536 | } 1537 | { 1538 | 1539 | Memcheck:Addr16 1540 | fun:kill_trailing 1541 | fun:nf_inq_varid_ 1542 | fun:mod_oasis_coupler_mp_oasis_coupler_smatreaddnc_ 1543 | fun:mod_oasis_coupler_mp_oasis_coupler_setup_ 1544 | fun:mod_oasis_method_mp_oasis_enddef_ 1545 | fun:cpl_interfaces_mp_init_cpl_ 1546 | fun:MAIN__ 1547 | fun:main 1548 | } 1549 | { 1550 | 1551 | Memcheck:Addr16 1552 | fun:kill_trailing 1553 | fun:nf_open_ 1554 | fun:netcdf_mp_nf90_open_ 1555 | fun:mod_oasis_io_mp_oasis_io_read_avfile_ 1556 | fun:mod_oasis_advance_mp_oasis_advance_run_ 1557 | fun:mod_oasis_advance_mp_oasis_advance_init_ 1558 | fun:mod_oasis_method_mp_oasis_enddef_ 1559 | fun:cpl_interfaces_mp_init_cpl_ 1560 | fun:MAIN__ 1561 | fun:main 1562 | } 1563 | { 1564 | 1565 | Memcheck:Addr16 1566 | fun:kill_trailing 1567 | fun:nf_inq_varid_ 1568 | fun:mod_oasis_io_mp_oasis_io_read_avfile_ 1569 | fun:mod_oasis_advance_mp_oasis_advance_run_ 1570 | fun:mod_oasis_advance_mp_oasis_advance_init_ 1571 | fun:mod_oasis_method_mp_oasis_enddef_ 1572 | fun:cpl_interfaces_mp_init_cpl_ 1573 | fun:MAIN__ 1574 | fun:main 1575 | } 1576 | { 1577 | 1578 | Memcheck:Addr16 1579 | fun:__intel_sse2_strlen 1580 | fun:kill_trailing 1581 | fun:nf_inq_var_ 1582 | fun:netcdf_mp_nf90_inquire_variable_ 1583 | fun:mod_oasis_io_mp_oasis_io_read_avfile_ 1584 | fun:mod_oasis_advance_mp_oasis_advance_run_ 1585 | fun:mod_oasis_advance_mp_oasis_advance_init_ 1586 | fun:mod_oasis_method_mp_oasis_enddef_ 1587 | fun:cpl_interfaces_mp_init_cpl_ 1588 | fun:MAIN__ 1589 | fun:main 1590 | } 1591 | { 1592 | 1593 | Memcheck:Addr16 1594 | fun:__intel_sse2_strlen 1595 | fun:kill_trailing 1596 | fun:nf_inq_dim_ 1597 | fun:netcdf_mp_nf90_inquire_dimension_ 1598 | fun:mod_oasis_io_mp_oasis_io_read_avfile_ 1599 | fun:mod_oasis_advance_mp_oasis_advance_run_ 1600 | fun:mod_oasis_advance_mp_oasis_advance_init_ 1601 | fun:mod_oasis_method_mp_oasis_enddef_ 1602 | fun:cpl_interfaces_mp_init_cpl_ 1603 | fun:MAIN__ 1604 | fun:main 1605 | } 1606 | { 1607 | 1608 | Memcheck:Addr16 1609 | fun:kill_trailing 1610 | fun:nf_open_ 1611 | fun:netcdf_mp_nf90_open_ 1612 | fun:mod_oasis_io_mp_oasis_io_read_avfile_ 1613 | fun:mod_oasis_advance_mp_oasis_advance_run_ 1614 | fun:mod_oasis_advance_mp_oasis_advance_init_ 1615 | fun:mod_oasis_method_mp_oasis_enddef_ 1616 | fun:cpl_interface_mp_init_cpl_ 1617 | fun:cice_initmod_mp_cice_init_ 1618 | fun:cice_initmod_mp_cice_initialize_ 1619 | fun:MAIN__ 1620 | fun:main 1621 | } 1622 | { 1623 | 1624 | Memcheck:Addr16 1625 | fun:kill_trailing 1626 | fun:nf_inq_varid_ 1627 | fun:mod_oasis_io_mp_oasis_io_read_avfile_ 1628 | fun:mod_oasis_advance_mp_oasis_advance_run_ 1629 | fun:mod_oasis_advance_mp_oasis_advance_init_ 1630 | fun:mod_oasis_method_mp_oasis_enddef_ 1631 | fun:cpl_interface_mp_init_cpl_ 1632 | fun:cice_initmod_mp_cice_init_ 1633 | fun:cice_initmod_mp_cice_initialize_ 1634 | fun:MAIN__ 1635 | fun:main 1636 | } 1637 | { 1638 | 1639 | Memcheck:Addr16 1640 | fun:__intel_sse2_strlen 1641 | fun:kill_trailing 1642 | fun:nf_inq_var_ 1643 | fun:netcdf_mp_nf90_inquire_variable_ 1644 | fun:mod_oasis_io_mp_oasis_io_read_avfile_ 1645 | fun:mod_oasis_advance_mp_oasis_advance_run_ 1646 | fun:mod_oasis_advance_mp_oasis_advance_init_ 1647 | fun:mod_oasis_method_mp_oasis_enddef_ 1648 | fun:cpl_interface_mp_init_cpl_ 1649 | fun:cice_initmod_mp_cice_init_ 1650 | fun:cice_initmod_mp_cice_initialize_ 1651 | fun:MAIN__ 1652 | fun:main 1653 | } 1654 | { 1655 | 1656 | Memcheck:Addr16 1657 | fun:__intel_sse2_strlen 1658 | fun:kill_trailing 1659 | fun:nf_inq_dim_ 1660 | fun:netcdf_mp_nf90_inquire_dimension_ 1661 | fun:mod_oasis_io_mp_oasis_io_read_avfile_ 1662 | fun:mod_oasis_advance_mp_oasis_advance_run_ 1663 | fun:mod_oasis_advance_mp_oasis_advance_init_ 1664 | fun:mod_oasis_method_mp_oasis_enddef_ 1665 | fun:cpl_interface_mp_init_cpl_ 1666 | fun:cice_initmod_mp_cice_init_ 1667 | fun:cice_initmod_mp_cice_initialize_ 1668 | fun:MAIN__ 1669 | fun:main 1670 | } 1671 | { 1672 | 1673 | Memcheck:Addr16 1674 | fun:__intel_sse2_strlen 1675 | fun:for__add_to_lf_table 1676 | fun:for__open_proc 1677 | fun:for_open 1678 | fun:mod_oasis_method_mp_oasis_init_comp_ 1679 | fun:cpl_interfaces_mp_prism_init_ 1680 | fun:MAIN__ 1681 | fun:main 1682 | } 1683 | { 1684 | 1685 | Memcheck:Addr16 1686 | fun:__intel_sse2_strcpy 1687 | fun:for__add_to_lf_table 1688 | fun:for__open_proc 1689 | fun:for_open 1690 | fun:mod_oasis_method_mp_oasis_init_comp_ 1691 | fun:cpl_interfaces_mp_prism_init_ 1692 | fun:MAIN__ 1693 | fun:main 1694 | } 1695 | -------------------------------------------------------------------------------- /tools/.pylintrc: -------------------------------------------------------------------------------- 1 | [MASTER] 2 | init-hook='import sys; sys.path.extend(["esmgrids","../test"])' 3 | -------------------------------------------------------------------------------- /tools/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Tools 3 | 4 | This directory contains a collection of tools which are used to make model input files. 5 | 6 | 7 | ## make\_remap\_weights.py 8 | 9 | This tool read the atmosphere and ice/ocean grid definitions and creates remapping weights files. These are used by the coupler to interpolate the fields between the model grids. The tool needs to be invoked once for each pair of grids and by default will create two weights files - one for conservative interpolation and one for patch interpolation. 10 | 11 | For example to create 1 deg JRA55 weights on a Gadi (NCI.org.au) head node: 12 | 13 | ``` 14 | module use /g/data3/hh5/public/modules 15 | module load conda/analysis27-18.10 16 | module load nco 17 | module load openmpi 18 | python ./make_remap_weights.py --help 19 | ``` 20 | 21 | Now to create the atmosphere to ice/ocean weights: 22 | 23 | ``` 24 | python ./make_remap_weights.py /g/data/qv56/replicas/input4MIPs/CMIP6/OMIP/MRI/MRI-JRA55-do-1-4-0/atmos/3hr/rsds/gr/v20190429/rsds/rsds_input4MIPs_atmosphericState_OMIP_MRI-JRA55-do-1-4-0_gr_195801010130-195812312230.nc JRA55 /g/data/ik11/inputs/access-om2/input_rc/mom_1deg/ MOM1 25 | ``` 26 | 27 | The above should result in two files in the currect directory: `JRA55_MOM1_conserve.nc` and `JRA55_MOM1_patch.nc` 28 | 29 | The following will create the weights needed for river runoff: 30 | 31 | ``` 32 | python ./make_remap_weights.py /g/data/qv56/replicas/input4MIPs/CMIP6/OMIP/MRI/MRI-JRA55-do-1-4-0/land/day/friver/gr/v20190429/friver_input4MIPs_atmosphericState_OMIP_MRI-JRA55-do-1-4-0_gr_19580101-19581231.nc JRA55_runoff /g/data/ik11/inputs/access-om2/input_rc/mom_1deg/ MOM1 33 | ``` 34 | 35 | The 0.25 deg weights can also be created on the head nodes - this ususally takes a few minutes: 36 | 37 | ``` 38 | python ./make_remap_weights.py /g/data/qv56/replicas/input4MIPs/CMIP6/OMIP/MRI/MRI-JRA55-do-1-4-0/atmos/3hr/rsds/gr/v20190429/rsds_input4MIPs_atmosphericState_OMIP_MRI-JRA55-do-1-4-0_gr_195801010130-195812312230.nc JRA55 /g/data/ik11/inputs/access-om2/input_rc/mom_025deg/ MOM025 39 | python ./make_remap_weights.py /g/data/qv56/replicas/input4MIPs/CMIP6/OMIP/MRI/MRI-JRA55-do-1-4-0/land/day/friver/gr/v20190429/friver_input4MIPs_atmosphericState_OMIP_MRI-JRA55-do-1-4-0_gr_19580101-19581231.nc JRA55_runoff /g/data/ik11/inputs/access-om2/input_rc/mom_025deg/ MOM025 40 | ``` 41 | 42 | To make the 0.1 deg weights we need to use more PEs and memory, first get an interactive job with lots of memory: 43 | 44 | ``` 45 | qsub -I -P v45 -q normal -lncpus=96 -lmem=348Gb -lwalltime=3:00:00 -lstorage=gdata/ua8+gdata/qv56+gdata/hh5+gdata/ik11 46 | ``` 47 | 48 | Then run the following commands, note the use of `--npes 96`. 49 | 50 | ``` 51 | cd access-om2/tools 52 | module use /g/data3/hh5/public/modules 53 | module load conda/analysis27-18.10 54 | module load nco 55 | module load openmpi 56 | time python ./make_remap_weights.py /g/data/qv56/replicas/input4MIPs/CMIP6/OMIP/MRI/MRI-JRA55-do-1-4-0/atmos/3hr/rsds/gr/v20190429/rsds_input4MIPs_atmosphericState_OMIP_MRI-JRA55-do-1-4-0_gr_195801010130-195812312230.nc JRA55 /g/data/ik11/inputs/access-om2/input_rc/mom_01deg/ MOM01 --npes 96 57 | 58 | ``` 59 | 60 | 61 | -------------------------------------------------------------------------------- /tools/add_core2_time_bounds.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import print_function 4 | 5 | """ 6 | The CORE2 forcing files have an ambiguous time dimension. For example in 7 | ncar_precip.0001.nc: 8 | 9 | TIME:units = "days since 1900-01-01 00:00:00" ; 10 | TIME = 15.5, 45, 74.5, 105, 135.5, 166, 196.5, 227.5, 258, 288.5, 319, 349.5 ; 11 | 12 | For a human this probably means that each time point refers to a month, however 13 | for a computer that is trying to index on the basis of a date and time it is 14 | ambiguous. For example which time point should be used for Jan 31? If an 15 | algorithm tries to find the 'closest' time point it will choose the second one, 16 | which is probably not the intention of the dataset. 17 | 18 | This script corrects this ambiguity by adding a time_bounds variable to define 19 | the time range than each point covers. 20 | 21 | Example invocation: 22 | 23 | python ./add_core2_time_bounds.py ../input/yatm_1deg/ncar_precip.0001.nc 24 | """ 25 | 26 | import sys 27 | import os 28 | import git 29 | import argparse 30 | import datetime 31 | import netCDF4 as nc 32 | 33 | def get_history_record(repo_dir): 34 | """Create a new history record.""" 35 | 36 | time_stamp = datetime.datetime.now().isoformat() 37 | exe = sys.executable 38 | args = " ".join(sys.argv) 39 | repo = git.Repo(repo_dir) 40 | git_url = str(list(repo.remote().urls)[0]) 41 | git_hash = str(repo.heads[0].commit)[0:7] 42 | 43 | entry = "{}: {} {} (Git URL: {}, Git hash: {})".format(time_stamp, exe, args, git_url, git_hash) 44 | 45 | return entry 46 | 47 | 48 | def main(): 49 | 50 | parser = argparse.ArgumentParser() 51 | parser.add_argument('input', help="Input CORE file without time_bounds variable.") 52 | args = parser.parse_args() 53 | 54 | with nc.Dataset(args.input, 'r+') as f: 55 | try: 56 | time = f.variables['TIME'] 57 | time_name = 'TIME' 58 | except KeyError as e: 59 | time = f.variables['Time'] 60 | time_name = 'Time' 61 | time.bounds = 'time_bnds' 62 | if os.path.basename(args.input) == 'runoff.daitren.clim.10FEB2011.nc': 63 | assert time.units == "days since 0001-01-01 00:00:00" 64 | time.units = "days since 1900-01-01 00:00:00" 65 | 66 | # Create extra dimension for time_bnds variable 67 | f.createDimension('time_bnds_dim', 2) 68 | time_bnds = f.createVariable('time_bnds', 'f8', (time_name, 'time_bnds_dim')) 69 | 70 | if len(time) == 12: 71 | # Assume this is monthly data and use hard-coded time_bounds. This 72 | # is necessary because ncar_precip and runoff have different dimensions 73 | # despite both being monthly. 74 | time_bnds[:, :] = [[0, 31], [31, 59], [59, 90], [90, 120], 75 | [120, 151], [151, 181], [181, 212], [212, 243], 76 | [243, 273], [273, 304], [304, 334], [334, 365]] 77 | else: 78 | # Calculate time bounds. 79 | for i, t in enumerate(time[:]): 80 | if i == 0: 81 | time_bnds[i, 0] = 0 82 | time_bnds[i, 1] = t*2 83 | else: 84 | time_bnds[i, 0] = time_bnds[i-1, 1] 85 | time_bnds[i, 1] = time_bnds[i, 0] + (time[i] - time_bnds[i-1, 1])*2 86 | 87 | # Update the file history. 88 | my_dir = dir_path = os.path.dirname(os.path.realpath(__file__)) 89 | history = get_history_record(os.path.join(my_dir, '../')) 90 | if hasattr(f, 'history'): 91 | f.history = '{} \n {}'.format(f.history, history) 92 | else: 93 | f.history = history 94 | 95 | if __name__ == "__main__": 96 | sys.exit(main()) 97 | -------------------------------------------------------------------------------- /tools/calc_input_checksum.py: -------------------------------------------------------------------------------- 1 | 2 | import sys 3 | import os 4 | import tempfile 5 | import tarfile 6 | import hashlib 7 | import argparse 8 | 9 | def calc_checksum(dirname): 10 | """ 11 | Calculate the checksum of a whole directory. 12 | 13 | This is done but tarring the directory first to make sure that file names 14 | and other metadata are included in the checksum. 15 | 16 | FIXME: this doesn't work, subsequent invokations of the function do not 17 | give the same value. This may be because the tmp file name is different 18 | each time. 19 | """ 20 | 21 | _, tmp = tempfile.mkstemp(suffix='.tar') 22 | with tarfile.open(tmp, "w") as tar: 23 | tar.add(dirname) 24 | 25 | h = hashlib.md5() 26 | 27 | with open(tmp, "rb") as f: 28 | for chunk in iter(lambda: f.read(4096), b""): 29 | h.update(chunk) 30 | 31 | # Delete tarball now that hash has been calculated. 32 | os.remove(tmp) 33 | 34 | return h.hexdigest()[:8] 35 | 36 | 37 | def main(): 38 | 39 | parser = argparse.ArgumentParser() 40 | parser.add_argument('dirpath', help='Path of directory whose checksum to return.') 41 | 42 | args = parser.parse_args() 43 | 44 | checksum = calc_checksum(args.dirpath) 45 | print(checksum) 46 | 47 | 48 | if __name__ == '__main__': 49 | sys.exit(main()) 50 | -------------------------------------------------------------------------------- /tools/contrib/build_esmf_on_raijin.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | git archive --remote=git://git.code.sf.net/p/esmf/esmf --format=tar --prefix=esmf/ ESMF_7_1_0r | tar xf - 4 | module load netcdf/4.4.1.1 5 | module load intel-fc/17.0.1.132 6 | mkdir -p bin 7 | cd esmf 8 | export ESMF_DIR=$(pwd) 9 | export ESMF_F90COMPILER=ifort 10 | export ESMF_F90LINKER=ifort 11 | export ESMF_NETCDF="split" 12 | export ESMF_NETCDF_INCLUDE=$NETCDF_ROOT/include 13 | export ESMF_NETCDF_LIBPATH=$NETCDF_ROOT/lib 14 | export ESMF_NETCDF_LIBS="-lnetcdff -lnetcdf" 15 | make 16 | cd src/apps/ESMF_RegridWeightGen 17 | make 18 | cd ../../../../ 19 | cp esmf/apps/appsO/*/ESMF_RegridWeightGen bin/ 20 | export PATH=$(pwd)/bin:$PATH 21 | -------------------------------------------------------------------------------- /tools/contrib/build_esmf_on_ubuntu.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | mkdir bin 4 | sudo apt-get install libnetcdf-dev libnetcdff-dev 5 | wget http://s3-ap-southeast-2.amazonaws.com/dp-drop/ocean-regrid/contrib/esmf_7_0_0_src.tar.gz 6 | tar zxvf esmf_7_0_0_src.tar.gz 7 | cd esmf 8 | export ESMF_DIR=$(pwd) 9 | export ESMF_NETCDF="split" 10 | export ESMF_NETCDF_INCLUDE=/usr/include/ 11 | export ESMF_NETCDF_LIBPATH=/usr/lib/x86_64-linux-gnu/ 12 | export ESMF_NETCDF_LIBS="-lnetcdff -lnetcdf" 13 | make 14 | cd src/apps/ESMF_RegridWeightGen 15 | make 16 | cd ../../../../ 17 | cp esmf/apps/appsO/*/ESMF_RegridWeightGen bin/ 18 | export PATH=$(pwd)/bin:$PATH 19 | -------------------------------------------------------------------------------- /tools/make_cice_grid.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | import os 5 | import argparse 6 | 7 | my_dir = os.path.dirname(os.path.realpath(__file__)) 8 | sys.path.append(os.path.join(my_dir, 'esmgrids')) 9 | 10 | from esmgrids.mom_grid import MomGrid # noqa 11 | from esmgrids.cice_grid import CiceGrid # noqa 12 | 13 | """ 14 | Create CICE grid.nc and kmt.nc from MOM ocean_hgrid.nc and ocean_mask.nc 15 | """ 16 | 17 | def main(): 18 | 19 | parser = argparse.ArgumentParser() 20 | parser.add_argument('ocean_hgrid', help='ocean_mask.nc file') 21 | parser.add_argument('ocean_mask', help='ocean_hgrid.nc file') 22 | 23 | args = parser.parse_args() 24 | 25 | mom = MomGrid.fromfile(args.ocean_hgrid, mask_file=args.ocean_mask) 26 | 27 | # FIXME: 28 | # MOM dx is at the cell centre while HTN is on the Northern boundary 29 | # MOM dy is at the cell centre while HTE is on the Eastern boundary 30 | cice = CiceGrid.fromgrid(mom) 31 | 32 | grid_file = os.path.join('grid.nc') 33 | mask_file = os.path.join('kmt.nc') 34 | cice.write(grid_file, mask_file) 35 | 36 | if __name__ == '__main__': 37 | sys.exit(main()) 38 | -------------------------------------------------------------------------------- /tools/make_remap_weights.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from __future__ import print_function 4 | 5 | import sys 6 | import os 7 | import shutil 8 | import shlex 9 | import argparse 10 | import netCDF4 as nc 11 | import numpy as np 12 | import tempfile 13 | import subprocess as sp 14 | import multiprocessing as mp 15 | 16 | my_dir = os.path.dirname(os.path.realpath(__file__)) 17 | sys.path.append(os.path.join(my_dir, './esmgrids')) 18 | 19 | from esmgrids.mom_grid import MomGrid # noqa 20 | from esmgrids.core2_grid import Core2Grid # noqa 21 | from esmgrids.jra55_grid import Jra55Grid # noqa 22 | from esmgrids.jra55_river_grid import Jra55RiverGrid # noqa 23 | from esmgrids.daitren_runoff_grid import DaitrenRunoffGrid # noqa 24 | 25 | """ 26 | This script makes all of the remapping weights for ACCESS-OM2. 27 | 28 | Run example: 29 | 30 | ./make_remap_weights.py /short/x77/nah599/access-om2/input/ \ 31 | /g/data/ua8/JRA55-do/RYF/v1-3/ 32 | """ 33 | 34 | def convert_to_scrip_output(weights): 35 | 36 | my_dir = os.path.dirname(os.path.realpath(__file__)) 37 | 38 | _, new_weights = tempfile.mkstemp(suffix='.nc', dir=my_dir) 39 | # So that ncrename doesn't prompt for overwrite. 40 | os.remove(new_weights) 41 | 42 | cmdstring = ('ncrename -d n_a,src_grid_size -d n_b,dst_grid_size -d n_s,' 43 | 'num_links -d nv_a,src_grid_corners -d nv_b,dst_grid_corner' 44 | 's -v yc_a,src_grid_center_lat -v yc_b,dst_grid_center_lat ' 45 | '-v xc_a,src_grid_center_lon -v xc_b,dst_grid_center_lon -v' 46 | ' yv_a,src_grid_corner_lat -v xv_a,src_grid_corner_lon -v y' 47 | 'v_b,dst_grid_corner_lat -v xv_b,dst_grid_corner_lon -v mas' 48 | 'k_a,src_grid_imask -v mask_b,dst_grid_imask -v area_a,src_' 49 | 'grid_area -v area_b,dst_grid_area -v frac_a,src_grid_frac ' 50 | '-v frac_b,dst_grid_frac -v col,src_address -v row,dst_addr' 51 | 'ess {} {}') 52 | cmd = cmdstring.format(weights, new_weights) 53 | 54 | try: 55 | sp.check_output(shlex.split(cmd)) 56 | except sp.CalledProcessError as e: 57 | print(cmd, file=sys.stderr) 58 | print(e.output, file=sys.stderr) 59 | return None 60 | 61 | # Fix the dimension of the remap_matrix. 62 | with nc.Dataset(weights) as f_old, nc.Dataset(new_weights, 'r+') as f_new: 63 | remap_matrix = f_new.createVariable('remap_matrix', 64 | 'f8', ('num_links', 'num_wgts')) 65 | remap_matrix[:, 0] = f_old.variables['S'][:] 66 | 67 | os.remove(weights) 68 | 69 | return new_weights 70 | 71 | 72 | def create_weights(src_grid, dest_grid, npes, method, 73 | ignore_unmapped=False, 74 | unmasked_src=True, unmasked_dest=False): 75 | 76 | my_dir = os.path.dirname(os.path.realpath(__file__)) 77 | 78 | _, src_grid_scrip = tempfile.mkstemp(suffix='.nc', dir=my_dir) 79 | _, dest_grid_scrip = tempfile.mkstemp(suffix='.nc', dir=my_dir) 80 | _, regrid_weights = tempfile.mkstemp(suffix='.nc', dir=my_dir) 81 | 82 | if unmasked_src: 83 | src_grid.write_scrip(src_grid_scrip, write_test_scrip=False, 84 | mask=np.zeros_like(src_grid.mask_t, dtype=int)) 85 | else: 86 | src_grid.write_scrip(src_grid_scrip, write_test_scrip=False) 87 | 88 | if unmasked_dest: 89 | dest_grid.write_scrip(dest_grid_scrip, write_test_scrip=False, 90 | mask=np.zeros_like(dest_grid.mask_t, dtype=int)) 91 | else: 92 | dest_grid.write_scrip(dest_grid_scrip, write_test_scrip=False) 93 | 94 | if ignore_unmapped: 95 | ignore_unmapped = ['--ignore_unmapped'] 96 | else: 97 | ignore_unmapped = [] 98 | 99 | try: 100 | cmd = ['mpirun', '-np', str(npes), 'ESMF_RegridWeightGen'] + \ 101 | ['--netcdf4', 102 | '-s', src_grid_scrip, 103 | '-d', dest_grid_scrip, '-m', method, 104 | '-w', regrid_weights] + ignore_unmapped 105 | print(cmd) 106 | sp.check_output(cmd) 107 | except sp.CalledProcessError as e: 108 | print("Error: ESMF_RegridWeightGen failed ret {}".format(e.returncode), 109 | file=sys.stderr) 110 | print(e.output, file=sys.stderr) 111 | log = 'PET0.RegridWeightGen.Log' 112 | if os.path.exists(log): 113 | print('Contents of {}:'.format(log), file=sys.stderr) 114 | with open(log) as f: 115 | print(f.read(), file=sys.stderr) 116 | return None 117 | 118 | os.remove(src_grid_scrip) 119 | os.remove(dest_grid_scrip) 120 | 121 | return regrid_weights 122 | 123 | 124 | def find_grid_defs(input_dir, jra55_input, core_input): 125 | """ 126 | Return a dictionary containing the grid definition files. 127 | """ 128 | 129 | d = {} 130 | d['MOM1'] = (os.path.join(input_dir, 'mom_1deg', 'ocean_hgrid.nc'), 131 | os.path.join(input_dir, 'mom_1deg', 'ocean_mask.nc')) 132 | d['MOM025'] = (os.path.join(input_dir, 'mom_025deg', 'ocean_hgrid.nc'), 133 | os.path.join(input_dir, 'mom_025deg', 'ocean_mask.nc')) 134 | d['MOM01'] = (os.path.join(input_dir, 'mom_01deg', 'ocean_hgrid.nc'), 135 | os.path.join(input_dir, 'mom_01deg', 'ocean_mask.nc')) 136 | d['CORE2'] = os.path.join(core_input, 't_10.0001.nc') 137 | d['JRA55'] = os.path.join(jra55_input, 'RYF.tas.1990_1991.nc') 138 | d['JRA55_runoff'] = os.path.join(jra55_input, 139 | 'RYF.runoff_all.1990_1991.nc') 140 | d['Daitren_runoff'] = os.path.join(core_input, 'runoff.daitren.clim.10FEB2011.nc') 141 | 142 | return d 143 | 144 | 145 | def main(): 146 | 147 | parser = argparse.ArgumentParser() 148 | parser.add_argument('input_dir', help=""" 149 | The ACCESS-OM2 input directory.""") 150 | parser.add_argument('jra55_input', help=""" 151 | The JRA55 input directory.""") 152 | parser.add_argument('core_input', help=""" 153 | The CORE input directory.""") 154 | parser.add_argument('--atm', default=None, help=""" 155 | Atmosphere grid to regrid from, can be one of: 156 | CORE2, JRA55, JRA55_runoff, Daitren_runoff""") 157 | parser.add_argument('--ocean', default=None, help=""" 158 | Ocean grid to regrid to, can be one of: 159 | MOM1, MOM01, MOM025""") 160 | parser.add_argument('--method', default=None, help=""" 161 | The interpolation method to use, can be patch, conserve or conserve2nd""") 162 | parser.add_argument('--npes', default=None, help=""" 163 | The number of PEs to use.""") 164 | parser.add_argument('--unmask_dest', 165 | action='store_true', 166 | help='Ignore destination grid mask') 167 | 168 | args = parser.parse_args() 169 | atm_options = ['JRA55', 'JRA55_runoff', 'CORE2', 'Daitren_runoff'] 170 | ocean_options = ['MOM1', 'MOM025', 'MOM01'] 171 | method_options = ['patch', 'conserve', 'conserve2nd'] 172 | 173 | if args.atm is None: 174 | args.atm = atm_options 175 | else: 176 | if args.atm not in atm_options: 177 | print("Error: bad atm grid.", file=sys.stderr) 178 | parser.print_help() 179 | return 1 180 | args.atm = [args.atm] 181 | 182 | if args.ocean is None: 183 | args.ocean = ocean_options 184 | else: 185 | if args.ocean not in ocean_options: 186 | print("Error: bad atm grid.", file=sys.stderr) 187 | parser.print_help() 188 | return 1 189 | args.ocean = [args.ocean] 190 | 191 | if args.method is None: 192 | args.method = method_options 193 | else: 194 | args.method = [args.method] 195 | 196 | if args.npes is None: 197 | import multiprocessing as mp 198 | args.npes = mp.cpu_count() // 2 199 | 200 | grid_file_dict = find_grid_defs(args.input_dir, args.jra55_input, args.core_input) 201 | 202 | for ocean in args.ocean: 203 | umask_file = grid_file_dict[ocean][1] 204 | dest_grid = MomGrid.fromfile(grid_file_dict[ocean][0], 205 | mask_file=umask_file) 206 | for atm in args.atm: 207 | 208 | if atm == 'CORE2': 209 | src_grid = Core2Grid(grid_file_dict[atm]) 210 | elif atm == 'Daitren_runoff': 211 | src_grid = DaitrenRunoffGrid(grid_file_dict[atm]) 212 | elif atm == 'JRA55': 213 | src_grid = Jra55Grid(grid_file_dict[atm]) 214 | elif atm == 'JRA55_runoff': 215 | src_grid = Jra55RiverGrid(grid_file_dict[atm], calc_areas=False) 216 | else: 217 | print('Unrecognised atmosphere grid: {}'.format(atm)) 218 | return 1 219 | 220 | for method in args.method: 221 | 222 | weights = create_weights(src_grid, dest_grid, args.npes, 223 | method, unmasked_dest=args.unmask_dest) 224 | if not weights: 225 | return 1 226 | weights = convert_to_scrip_output(weights) 227 | if not weights: 228 | return 1 229 | 230 | shutil.move(weights, '{}_{}_{}.nc'.format(atm, ocean, method)) 231 | 232 | return 0 233 | 234 | if __name__ == "__main__": 235 | sys.exit(main()) 236 | -------------------------------------------------------------------------------- /tools/make_remap_weights.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #PBS -P x77 3 | #PBS -q normal 4 | #PBS -l ncpus=256,mem=512GB,walltime=05:00:00,jobfs=100GB 5 | #PBS -l storage=gdata/hh5+gdata/ik11 6 | #PBS -l wd 7 | 8 | module purge 9 | module load openmpi 10 | module load nco 11 | module load esmf/8.1.0 12 | module use /g/data/hh5/public/modules 13 | module load conda/analysis3 14 | 15 | # Make all 1 deg weights. 16 | time ./make_remap_weights.py /short/x77/nah599/access-om2/input/ /g/data/ua8/JRA55-do/RYF/v1-3/ /short/x77/nah599/access-om2/input/yatm_1deg/ --ocean MOM1 --npes 256 17 | 18 | # Make all 0.25 deg weights. 19 | time ./make_remap_weights.py /short/x77/nah599/access-om2/input/ /g/data/ua8/JRA55-do/RYF/v1-3/ /short/x77/nah599/access-om2/input/yatm_1deg/ --ocean MOM025 --npes 256 20 | 21 | # Make all 0.1 deg weights. 22 | time ./make_remap_weights.py /short/x77/nah599/access-om2/input/ /g/data/ua8/JRA55-do/RYF/v1-3/ /short/x77/nah599/access-om2/input/yatm_1deg/ --ocean MOM01 --npes 256 23 | -------------------------------------------------------------------------------- /tools/make_salt_sfc_restore.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import numpy as np 4 | import sys 5 | import numba 6 | import os 7 | import argparse 8 | import netCDF4 as nc 9 | import shutil 10 | from scipy.ndimage.filters import uniform_filter 11 | from make_remap_weights import create_weights 12 | 13 | from esmgrids.mom_grid import MomGrid # noqa 14 | from esmgrids.woa_grid import WoaGrid # noqa 15 | 16 | """ 17 | Create MOM salt_sfc_restore.nc file from WOA 18 | """ 19 | 20 | def calc_regridding_err(weights, src, dest): 21 | """ 22 | Calculate the regridding error. 23 | """ 24 | 25 | EARTH_RADIUS = 6370997.0 26 | 27 | with nc.Dataset(weights) as f: 28 | try: 29 | area_a = f.variables['area_a'][:] 30 | except KeyError as e: 31 | area_a = f.variables['src_grid_area'][:] 32 | area_a = area_a.reshape(src.shape[0], src.shape[1]) 33 | area_a = area_a*EARTH_RADIUS**2 34 | 35 | try: 36 | area_b = f.variables['area_b'][:] 37 | except KeyError as e: 38 | area_b = f.variables['dst_grid_area'][:] 39 | area_b = area_b.reshape(dest.shape[0], dest.shape[1]) 40 | area_b = area_b*EARTH_RADIUS**2 41 | 42 | try: 43 | frac_a = f.variables['frac_a'][:] 44 | except KeyError as e: 45 | frac_a = f.variables['src_grid_frac'][:] 46 | frac_a = frac_a.reshape(src.shape[0], src.shape[1]) 47 | 48 | try: 49 | frac_b = f.variables['frac_b'][:] 50 | except KeyError as e: 51 | frac_b = f.variables['dst_grid_frac'][:] 52 | frac_b = frac_b.reshape(dest.shape[0], dest.shape[1]) 53 | 54 | # Calculation of totals here. 55 | # http://www.earthsystemmodeling.org/esmf_releases/non_public/ESMF_5_3_0/ESMC_crefdoc/node3.html 56 | src_tot = np.sum(src[:, :] * area_a[:, :] * frac_a[:, :]) 57 | dest_tot = np.sum(dest[:, :] * area_b[:, :]) 58 | rel_err = abs(src_tot - dest_tot) / dest_tot 59 | 60 | return rel_err 61 | 62 | @numba.jit 63 | def apply_weights(src, dest_shape, n_s, n_b, row, col, s): 64 | """ 65 | Apply ESMF regirdding weights. 66 | """ 67 | 68 | dest = np.ndarray(dest_shape).flatten() 69 | dest[:] = 0.0 70 | src = src.flatten() 71 | 72 | for i in range(n_s): 73 | dest[row[i]-1] = dest[row[i]-1] + s[i]*src[col[i]-1] 74 | 75 | return dest.reshape(dest_shape) 76 | 77 | 78 | def remap(src_data, weights, dest_shape): 79 | """ 80 | Regrid a 2d field and see how it looks. 81 | """ 82 | 83 | dest_data = np.ndarray(dest_shape) 84 | 85 | with nc.Dataset(weights) as wf: 86 | try: 87 | n_s = wf.dimensions['n_s'].size 88 | except KeyError as e: 89 | n_s = wf.dimensions['num_links'].size 90 | try: 91 | n_b = wf.dimensions['n_b'].size 92 | except KeyError as e: 93 | n_b = wf.dimensions['dst_grid_size'].size 94 | try: 95 | row = wf.variables['row'][:] 96 | except KeyError as e: 97 | row = wf.variables['dst_address'][:] 98 | try: 99 | col = wf.variables['col'][:] 100 | except KeyError as e: 101 | col = wf.variables['src_address'][:] 102 | 103 | s = wf.variables['S'][:] 104 | 105 | dest_data[:, :] = apply_weights(src_data[:, :], dest_data.shape, 106 | n_s, n_b, row, col, s) 107 | return dest_data 108 | 109 | 110 | def smooth2d(src): 111 | 112 | tmp_src = np.ndarray((src.shape[0] + 6, src.shape[1])) 113 | 114 | # Window size 115 | ws = 3 116 | 117 | tmp_src[ws:-ws, :] = src[:, :] 118 | tmp_src[:ws, :] = src[-ws:, :] 119 | tmp_src[-ws:, :] = src[:3, :] 120 | 121 | dest = uniform_filter(tmp_src, size=ws, mode='nearest') 122 | return dest[ws:-ws, :] 123 | 124 | 125 | def main(): 126 | 127 | parser = argparse.ArgumentParser() 128 | parser.add_argument('woa_input', help='The WOA input file.') 129 | parser.add_argument('ocean_hgrid', 130 | help='The horizontal MOM grid definition to remap to') 131 | parser.add_argument('old_salt_sfc_restore', 132 | help='The old salt sfc restoring file. Needed for metadata.') 133 | parser.add_argument('output', help='salt_sfc_restore.nc file for MOM5') 134 | parser.add_argument('--interpolation_weights', default=None, 135 | help='Interpolation weights, file if not given this will be created.') 136 | parser.add_argument('--method', default='patch', help=""" 137 | Interpolation method, passed to ESMF_RegridWeightGen.""") 138 | parser.add_argument('--npes', default=None, help=""" 139 | The number of PEs to use. Default is 1/2 of available.""") 140 | 141 | 142 | args = parser.parse_args() 143 | 144 | if args.npes is None: 145 | import multiprocessing as mp 146 | args.npes = mp.cpu_count() // 2 147 | 148 | src_grid = WoaGrid(args.woa_input, calc_areas=False) 149 | dest_grid = MomGrid.fromfile(args.ocean_hgrid, calc_areas=False) 150 | dest_res = (dest_grid.num_lat_points, dest_grid.num_lon_points) 151 | 152 | if args.interpolation_weights is None: 153 | weights = create_weights(src_grid, dest_grid, args.npes, args.method) 154 | else: 155 | weights = args.interpolation_weights 156 | 157 | with nc.Dataset(args.woa_input) as f: 158 | src = f.variables['so'][:] 159 | 160 | dest = np.zeros((src.shape[0], dest_res[0], dest_res[1])) 161 | 162 | for t in range(src.shape[0]): 163 | smooth_src = smooth2d(src[t, :, :]) 164 | dest[t, :, :] = remap(smooth_src, weights, dest_res) 165 | 166 | if 'conserve' in args.method: 167 | rel_err = calc_regridding_err(weights, smooth_src, dest[t, :, :]) 168 | print('relative error {}'.format(rel_err)) 169 | assert rel_err < 1e-14 170 | 171 | shutil.copyfile(args.old_salt_sfc_restore, args.output) 172 | with nc.Dataset(args.output, 'r+') as f: 173 | f.variables['salt'][:] = dest 174 | 175 | if __name__ == '__main__': 176 | sys.exit(main()) 177 | -------------------------------------------------------------------------------- /tools/release.py: -------------------------------------------------------------------------------- 1 | 2 | from __future__ import print_function 3 | 4 | import os 5 | import sys 6 | import re 7 | import shutil 8 | import stat 9 | import argparse 10 | import distutils.dir_util 11 | import tempfile 12 | from calc_input_checksum import calc_checksum 13 | 14 | my_path = os.path.dirname(os.path.realpath(__file__)) 15 | sys.path.append(os.path.join(my_path, '../', 'test')) 16 | from exp_test_helper import ExpTestHelper 17 | 18 | EXP_NAMES = ['01deg_jra55_ryf', '01deg_jra55_iaf', 19 | '1deg_jra55_ryf', '1deg_jra55_iaf', 20 | '025deg_jra55_ryf', '025deg_jra55_iaf'] 21 | 22 | def update_payu_config(exp_name, res, payu_config, yatm_exe, cice_exe, mom_exe, input_dir=None): 23 | """ 24 | Set the new input_dirs and exes in payu config.yaml 25 | """ 26 | 27 | _, tmp = tempfile.mkstemp() 28 | 29 | with open(payu_config) as fs, open(tmp, 'r+') as fd: 30 | cur_model = None 31 | for line in fs: 32 | m = re.search('^[\s-]*name:\s+(\S+)', line) 33 | if m: 34 | cur_model = m.group(1) 35 | 36 | if re.search('collate', line): 37 | cur_model = 'collate' 38 | 39 | m_exe = re.search('^\s*exe:\s+\S+', line) 40 | if input_dir: 41 | m_input = re.search('^\s*input:\s+\S+', line) 42 | else: 43 | m_input = None 44 | 45 | if m_exe: 46 | assert cur_model 47 | if cur_model == 'atmosphere': 48 | print(' exe: {}'.format(yatm_exe), file=fd) 49 | elif cur_model == 'ocean': 50 | print(' exe: {}'.format(mom_exe), file=fd) 51 | elif cur_model == 'ice': 52 | print(' exe: {}'.format(cice_exe), file=fd) 53 | else: 54 | print(line, file=fd, end='') 55 | elif m_input: 56 | assert cur_model 57 | if cur_model == 'common': 58 | if 'jra55' in exp_name: 59 | common_input = os.path.join(input_dir, 'common_{}_{}'.format(res, 'jra55')) 60 | else: 61 | common_input = os.path.join(input_dir, 'common_{}_{}'.format(res, 'core')) 62 | print('input: {}'.format(common_input), file=fd) 63 | elif cur_model == 'atmosphere': 64 | yatm_input = os.path.join(input_dir, 'yatm_{}'.format(res)) 65 | print(' input: {}'.format(yatm_input), file=fd) 66 | elif cur_model == 'ocean': 67 | mom_input = os.path.join(input_dir, 'mom_{}'.format(res)) 68 | print(' input: {}'.format(mom_input), file=fd) 69 | elif cur_model == 'ice': 70 | cice_input = os.path.join(input_dir, 'cice_{}'.format(res)) 71 | print(' input: {}'.format(cice_input), file=fd) 72 | else: 73 | print(line, file=fd, end='') 74 | else: 75 | print(line, file=fd, end='') 76 | 77 | shutil.copy(tmp, payu_config) 78 | 79 | 80 | def set_input_perms_recursively(path): 81 | 82 | dirperms = stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH | stat.S_IXUSR \ 83 | | stat.S_IXGRP | stat.S_IXOTH 84 | shutil.chown(path, group='v45') 85 | os.chmod(path, dirperms) 86 | 87 | for root, dirs, files in os.walk(path): 88 | for d in dirs: 89 | dirname = os.path.join(root, d) 90 | shutil.chown(dirname, group='ik11') 91 | os.chmod(dirname, dirperms) 92 | for f in files: 93 | fname = os.path.join(root, f) 94 | shutil.chown(fname, group='ik11') 95 | perms = stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH 96 | os.chmod(fname, perms) 97 | 98 | 99 | def update_input_data(): 100 | 101 | input_template = '/g/data/ik11/inputs/access-om2/input_{}' 102 | input_rc = input_template.format('rc') 103 | 104 | checksum = calc_checksum(input_rc) 105 | input_chksum = input_template.format(checksum) 106 | 107 | # Copy release candidate (rc) to dirctory with checksum 108 | if not os.path.exists(input_chksum): 109 | # For some reason shutil.copytree() doesn't work here. 110 | distutils.dir_util.copy_tree(input_rc, input_chksum, preserve_symlinks=True) 111 | 112 | # Fix up permissions. 113 | set_input_perms_recursively(input_chksum) 114 | 115 | return input_chksum 116 | 117 | 118 | def do_release(update_input_data=False): 119 | 120 | if update_input_data: 121 | input_dir = update_input_data() 122 | else: 123 | input_dir = None 124 | 125 | for exp_name in EXP_NAMES: 126 | 127 | # Build new exes. 128 | exp = ExpTestHelper(exp_name, bin_path='/g/data/ik11/inputs/access-om2/bin/') 129 | (yatm_exe, cice_exe, mom_exe), ret = exp.build() 130 | if ret != 0: 131 | print('Build failed for exp {}'.format(exp_name), file=sys.stderr) 132 | assert ret == 0 133 | 134 | update_payu_config(exp.exp_name, exp.res, exp.payu_config, yatm_exe, cice_exe, mom_exe, input_dir) 135 | 136 | def main(): 137 | 138 | parser = argparse.ArgumentParser() 139 | parser.add_argument('--update_input', default=False, action='store_true', 140 | help='Update experiment input directories as well.') 141 | 142 | args = parser.parse_args() 143 | 144 | do_release(update_input_data=args.update_input) 145 | 146 | 147 | if __name__ == '__main__': 148 | sys.exit(main()) 149 | 150 | 151 | --------------------------------------------------------------------------------